Add build related files etc. to OData folder:
    build.cmd
    WebApiOData.msbuild
    WebApiOData.sln
    .nuget
    tools
    src
        Common (some depending files, e.g., for Error.ArgumentNull)
        CommonAssemblyInfo.cs
        GlobalSuppressions.cs
        Settings.StyleCop
        Strict.ruleset
    test
        Common (ContextUtil.cs, MediaTypeFormatterTestBase.cs)
        Microsoft.TestCommon (a .csproj contains xUnit ref, Assert etc.)
        Settings.StyleCop

Change project references to nuget ref:
    System.Net.Http.Formatting
    System.Web.Http
    =>
    src packages.config:
      <package id="Microsoft.AspNet.WebApi.Client" version="5.2.0" targetFramework="net45" />
      <package id="Microsoft.AspNet.WebApi.Core" version="5.2.0" targetFramework="net45" />

    test packages.config:
    +  <package id="Microsoft.AspNet.WebApi.SelfHost" version="5.2.0" targetFramework="net45" />

Remove OData src and test projects from Runtime.sln and repositories.config

Build succeeds, all test cases pass.
This commit is contained in:
Congyong Su 2014-07-30 12:58:58 +08:00
Родитель fb3529258c
Коммит 27e6385349
134 изменённых файлов: 12717 добавлений и 91 удалений

11
OData/.nuget/NuGet.Config Normal file
Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<packageSources>
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
<add key="buildTools" value="https://www.myget.org/F/30de4ee06dd54956a82013fa17a3accb/" />
<add key="externalComponentDependencies" value="https://www.myget.org/F/02a8fd0d231848d2ae32cd901e273000" />
</packageSources>
</configuration>

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Web.SkipStrongNames" version="1.0.0" />
<package id="Microsoft.Web.StyleCop" version="1.0.0" />
<package id="StyleCop" version="4.7.10.0" />
</packages>

392
OData/Settings.StyleCop Normal file
Просмотреть файл

@ -0,0 +1,392 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">NoMerge</StringProperty>
</GlobalSettings>
<Parsers>
<Parser ParserId="StyleCop.CSharp.CsParser">
<ParserSettings>
<BooleanProperty Name="AnalyzeDesignerFiles">False</BooleanProperty>
</ParserSettings>
</Parser>
</Parsers>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="FieldNamesMustNotBeginWithUnderscore">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>db</Value>
<Value>dc</Value>
<Value>do</Value>
<Value>ef</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>is</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>sl</Value>
<Value>to</Value>
<Value>ui</Value>
<Value>vs</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustContainFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveValidCompanyText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationHeadersMustNotContainBlankLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustContainValidXml">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementDocumentationMustHaveSummaryText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustMatchElementParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="VoidReturnValueMustNotBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="GenericTypeParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustNotBeEmpty">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationMustMeetCharacterPercentage">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludedDocumentationXPathDoesNotExist">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="InheritDocMustBeUsedWithInheritingClass">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustHaveCopyrightText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderFileNameDocumentationMustMatchTypeName">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings>
<BooleanProperty Name="IgnorePrivates">True</BooleanProperty>
<BooleanProperty Name="IgnoreInternals">True</BooleanProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="ParameterMustNotSpanMultipleLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PrefixLocalCallsWithThis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustFollowComma">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="UseBuiltInTypeAlias">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.Web.StyleCop.Rules">
<AnalyzerSettings>
<StringProperty Name="FileHeaderText"> Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.</StringProperty>
</AnalyzerSettings>
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
<Rules>
<Rule Name="AllAccessorsMustBeMultiLineOrSingleLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentsMustNotBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ClosingCurlyBracketMustBeFollowedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SingleLineCommentMustBePrecededByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeSeparatedByBlankLine">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.MaintainabilityRules">
<Rules>
<Rule Name="FieldsMustBePrivate">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DebugAssertMustProvideMessageText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StatementMustNotUseUnnecessaryParenthesis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.OrderingRules">
<Rules>
<Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustAppearInTheCorrectOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeOrderedByAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstantsMustAppearBeforeFields">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StaticElementsMustAppearBeforeInstanceElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.SpacingRules">
<Rules>
<Rule Name="SingleLineCommentsMustBeginWithSingleSpace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="Microsoft.Web.StyleCop.Rules">
<Rules />
<AnalyzerSettings>
<StringProperty Name="FileHeaderText"> Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.</StringProperty>
</AnalyzerSettings>
</Analyzer>
</Analyzers>
</StyleCopSettings>

119
OData/WebApiOData.msbuild Normal file
Просмотреть файл

@ -0,0 +1,119 @@
<Project DefaultTargets="UnitTest" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="tools/WebStack.tasks.targets"/>
<UsingTask TaskName="SkipStrongNames.CheckSkipStrongNamesStatus" AssemblyFile="$(SkipStrongNamesExe)" />
<PropertyGroup>
<!-- build.cmd sets /p:Desktop=true. The CI server does not; instead, it does an additional step with /p:Configuration=CodeAnalysis. -->
<Configuration Condition=" '$(Configuration)' == '' and '$(Desktop)' == 'true' ">CodeAnalysis</Configuration>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<CodeAnalysis Condition=" '$(CodeAnalysis)' == '' and '$(Configuration)' != 'Release' ">true</CodeAnalysis>
<StyleCopEnabled Condition=" '$(StyleCopEnabled)' == '' ">true</StyleCopEnabled>
<BuildPortable Condition=" '$(BuildPortable)' == '' ">true</BuildPortable>
<BuildInParallel Condition=" '$(BuildInParallel)' == '' And $(MSBuildNodeCount) &gt; 1 ">true</BuildInParallel>
<BuildInParallel Condition=" '$(BuildInParallel)' == '' ">false</BuildInParallel>
<TestResultsDirectory>$(MSBuildThisFileDirectory)bin\$(Configuration)\test\TestResults\</TestResultsDirectory>
<SkipStrongNamesExe>$(MSBuildThisFileDirectory)packages\Microsoft.Web.SkipStrongNames.1.0.0\tools\SkipStrongNames.exe</SkipStrongNamesExe>
<SkipStrongNamesXml>$(MSBuildThisFileDirectory)tools\SkipStrongNames.xml</SkipStrongNamesXml>
<NuGetExe>.nuget\NuGet.exe</NuGetExe>
</PropertyGroup>
<ItemGroup>
<SolutionsToBuild Include="WebApiOData.sln">
<BuildInParallel>$(BuildInParallel)</BuildInParallel>
</SolutionsToBuild>
</ItemGroup>
<Target Name="EnableSkipStrongNames" DependsOnTargets="RestoreSkipStrongNames">
<Exec Command='"$(SkipStrongNamesExe)" -e "$(SkipStrongNamesXml)"' />
<CheckSkipStrongNamesStatus AssembliesFile="$(SkipStrongNamesXml)">
<Output TaskParameter="Status" PropertyName="Status" />
</CheckSkipStrongNamesStatus>
<Message Text="SkipStrongNames: $(Status)" Importance="High" />
</Target>
<Target Name="DisableSkipStrongNames" DependsOnTargets="RestoreSkipStrongNames">
<Exec Command='"$(SkipStrongNamesExe)" -d "$(SkipStrongNamesXml)"' />
<CheckSkipStrongNamesStatus AssembliesFile="$(SkipStrongNamesXml)">
<Output TaskParameter="Status" PropertyName="Status" />
</CheckSkipStrongNamesStatus>
<Message Text="SkipStrongNames: $(Status)" Importance="High" />
</Target>
<Target Name="Integration" DependsOnTargets="Clean;Build;UnitTest" />
<Target Name="Clean">
<MSBuild
Projects="@(SolutionsToBuild)"
Targets="Clean"
Condition=" '%(SolutionsToBuild.Portable)' != 'true' or '$(BuildPortable)' == 'true' "
Properties="Configuration=$(Configuration);VisualStudioVersion=$(VisualStudioVersion)" />
<RemoveDir Directories="bin\$(Configuration)" />
</Target>
<Target Name="DownloadNuGet">
<DownloadNuGet OutputFileName="$(NuGetExe)" MinimumVersion="2.7.0" />
</Target>
<Target Name="RestoreSkipStrongNames" DependsOnTargets="DownloadNuGet">
<Exec Command='"$(NuGetExe)" restore .nuget\packages.config -PackagesDirectory packages -NonInteractive -Verbosity quiet -ConfigFile .nuget\NuGet.Config' />
</Target>
<Target Name="RestorePackages" DependsOnTargets="DownloadNuGet">
<Message Text="Restoring NuGet packages..." Importance="High" />
<Exec Command='"$(NuGetExe)" restore "%(SolutionsToBuild.Identity)" -PackagesDirectory packages -NonInteractive -Verbosity quiet -ConfigFile "$(MsBuildThisFileDirectory)\.nuget\NuGet.Config"' />
<!-- Pick the right Microsoft.Web.FxCop package to use and copy it to a standard location. -->
</Target>
<Target Name="BuildTools">
<PropertyGroup>
<FxCopProjectLocation>$(MsBuildThisFileDirectory)tools\src\Microsoft.Web.FxCop\</FxCopProjectLocation>
<CustomFxCopRulesPath>$(MsBuildThisFileDirectory)packages\CustomFxCopRules</CustomFxCopRulesPath>
</PropertyGroup>
<MsBuild
Condition=" '$(CodeAnalysis)' == 'true' "
Projects="$(FxCopProjectLocation)\Microsoft.Web.FxCop.csproj"
Properties="Configuration=Release;OutputPath=$(CustomFxCopRulesPath)" />
</Target>
<Target Name="Build" DependsOnTargets="RestorePackages;BuildTools">
<!-- we need to batch the solution files since they both build Microsoft.TestCommon -->
<Error Condition=" '$(CodeAnalysis)' == 'true' and '$(Configuration)' == 'Release' " Text="Unable to run code analysis in Release configuration. Release assemblies do not include SuppressMessage attributes (so code analysis would always fail with the errors that are normally suppressed)." />
<MakeDir Directories="bin\$(Configuration)" />
<MSBuild
Projects="@(SolutionsToBuild)"
BuildInParallel="%(SolutionsToBuild.BuildInParallel)"
Targets="Build"
Condition=" '%(SolutionsToBuild.Portable)' != 'true' or '$(BuildPortable)' == 'true' "
Properties="Configuration=$(Configuration);CodeAnalysis=$(CodeAnalysis);StyleCopEnabled=$(StyleCopEnabled);VisualStudioVersion=$(VisualStudioVersion)" />
</Target>
<Target Name="UnitTest" DependsOnTargets="CheckSkipStrongNames;Build">
<CallTarget Targets="RunTests;PrintTestRunSummary" RunEachTargetSeparately="True" />
</Target>
<Target Name="RunTests" DependsOnTargets="CheckSkipStrongNames">
<ItemGroup>
<TestDLLsXunit Include="bin\$(Configuration)\test\*.Test.dll;bin\$(Configuration)\test\*.Test.*.dll;bin\$(Configuration)\Test\NetCore\*.Test.dll" />
<XunitProject Include="tools\WebStack.xunit.targets">
<Properties>TestAssembly=%(TestDLLsXunit.FullPath);XmlPath=$(TestResultsDirectory)%(TestDLLsXunit.FileName)-XunitResults.xml</Properties>
</XunitProject>
</ItemGroup>
<!-- Re-create the test results directory so that print summary doesn't run on old test results -->
<RemoveDir Directories="$(TestResultsDirectory)" />
<MakeDir Directories="$(TestResultsDirectory)" />
<MSBuild Projects="@(XunitProject)" BuildInParallel="$(BuildInParallel)" Targets="Xunit" />
</Target>
<Target Name="CheckSkipStrongNames" DependsOnTargets="RestoreSkipStrongNames">
<CheckSkipStrongNamesStatus AssembliesFile="$(SkipStrongNamesXml)">
<Output TaskParameter="Status" PropertyName="Status" />
</CheckSkipStrongNamesStatus>
<Error Text="Unit tests will not run correctly unless SkipStrongNames is Enabled. Current status: $(Status). Run build.cmd EnableSkipStrongNames to fix this problem." Condition="'$(Status)' != 'Enabled'" />
</Target>
<Target Name="PrintTestRunSummary">
<PrintTestRunSummary TestResultsDirectory="$(TestResultsDirectory)" />
</Target>
</Project>

74
OData/WebApiOData.sln Normal file
Просмотреть файл

@ -0,0 +1,74 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C40883CD-366D-4534-8B58-3EA0D13136DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.OData", "src\System.Web.Http.OData\System.Web.Http.OData.csproj", "{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.OData.Test", "test\System.Web.Http.OData.Test\System.Web.Http.OData.Test.csproj", "{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{CB34D534-9A09-4EE4-B350-C1C23AFBF5EE}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.OData", "src\System.Web.OData\System.Web.OData.csproj", "{D23E28F1-CCD0-43E0-8C0D-36731EC91318}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.OData.Test", "test\System.Web.OData.Test\System.Web.OData.Test.csproj", "{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeAnalysis|Any CPU = CodeAnalysis|Any CPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.Build.0 = Release|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}.Release|Any CPU.Build.0 = Release|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9}.Release|Any CPU.Build.0 = Release|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D23E28F1-CCD0-43E0-8C0D-36731EC91318}.Release|Any CPU.Build.0 = Release|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.CodeAnalysis|Any CPU.ActiveCfg = CodeAnalysis|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.CodeAnalysis|Any CPU.Build.0 = CodeAnalysis|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} = {C40883CD-366D-4534-8B58-3EA0D13136DF}
{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93}
{D344485F-F8CA-4B02-AF3D-D9C6FD556CA9} = {C40883CD-366D-4534-8B58-3EA0D13136DF}
{D23E28F1-CCD0-43E0-8C0D-36731EC91318} = {A9836F9E-6DB3-4D9F-ADCA-CF42D8C8BA93}
{66EFD03D-95B7-4C7E-83AC-1A8BD6C12612} = {C40883CD-366D-4534-8B58-3EA0D13136DF}
EndGlobalSection
EndGlobal

39
OData/build.cmd Normal file
Просмотреть файл

@ -0,0 +1,39 @@
@echo off
pushd %~dp0
setlocal
if exist bin goto build
mkdir bin
:Build
REM Find the most recent 32bit MSBuild.exe on the system. Require v12.0 (installed with VS2013) or later since .NET 4.0
REM is not supported. Also handle x86 operating systems, where %ProgramFiles(x86)% is not defined. Always quote the
REM %MSBuild% value when setting the variable and never quote %MSBuild% references.
set MSBuild="%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe"
if not exist %MSBuild% @set MSBuild="%ProgramFiles%\MSBuild\12.0\Bin\MSBuild.exe"
if "%1" == "" goto BuildDefaults
%MSBuild% WebApiOData.msbuild /m /nr:false /t:%* /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal
if %ERRORLEVEL% neq 0 goto BuildFail
goto BuildSuccess
:BuildDefaults
%MSBuild% WebApiOData.msbuild /m /nr:false /p:Platform="Any CPU" /p:Desktop=true /v:M /fl /flp:LogFile=bin\msbuild.log;Verbosity=Normal
if %ERRORLEVEL% neq 0 goto BuildFail
goto BuildSuccess
:BuildFail
echo.
echo *** BUILD FAILED ***
goto End
:BuildSuccess
echo.
echo **** BUILD SUCCESSFUL ***
goto end
:End
popd
endlocal

Просмотреть файл

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\src\System.Web.Http.OData\packages.config" />
<repository path="..\src\System.Web.OData\packages.config" />
<repository path="..\test\Microsoft.TestCommon\packages.config" />
<repository path="..\test\System.Web.Http.OData.Test\packages.config" />
<repository path="..\test\System.Web.OData.Test\packages.config" />
</repositories>

Просмотреть файл

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8" ?>
<Dictionary>
<Words>
<Recognized>
<Word>Multi</Word>
<Word>Bitly</Word>
<Word>Digg</Word>
<Word>Facebook</Word>
<Word>Reddit</Word>
<Word>Captcha</Word>
<Word>Facebook</Word>
<Word>Gravatar</Word>
<Word>JSON</Word>
<Word>Lookahead</Word>
<Word>MVC</Word>
<Word>Param</Word>
<Word>Params</Word>
<Word>Pluralizer</Word>
<Word>Pragma</Word>
<Word>Pragmas</Word>
<Word>Templating</Word>
<Word>Unvalidated</Word>
<Word>Validator</Word>
<Word>Validators</Word>
<Word>Validatable</Word>
<Word>WebPage</Word>
<Word>cshtml</Word>
<Word>vbhtml</Word>
<Word>asax</Word>
<Word>Eval</Word>
<Word>Src</Word>
<Word>Charset</Word>
<Word>Coords</Word>
<Word>Rel</Word>
<Word>Dto</Word>
<Word>Tokenizer</Word>
<Word>ReDim</Word>
<Word>OAuth</Word>
<Word>OpenID</Word>
<Word>Yadis</Word>
<Word>fwlink</Word>
<Word>Edm</Word>
<Word>Deserializer</Word>
<Word>Api</Word>
<Word>ws</Word>
<Word>enc</Word>
<Word>dir</Word>
<Word>Auth</Word>
<Word>bg</Word>
<Word>Cors</Word>
<Word>Owin</Word>
<Word>Unbuffered</Word>
<Word>Rfc</Word>
<Word>Realtime</Word>
<Word>ModelName</Word>
<Word>BSON</Word>
<Word>Untyped</Word>
</Recognized>
<Compound>
<Term CompoundAlternate="WebPage">WebPage</Term>
<Term CompoundAlternate="WebPages">WebPages</Term>
<Term CompoundAlternate="TimeLine">TimeLine</Term>
<Term CompoundAlternate="OAuth">oAuth</Term>
<Term CompoundAlternate="UserName">userName</Term>
<Term CompoundAlternate="ModelName">modelName</Term>
<Term CompoundAlternate="HasId">HasId</Term>
</Compound>
</Words>
<Acronyms>
<CasingExceptions>
<Acronym>ID</Acronym>
<Acronym>Db</Acronym>
<Acronym>Dto</Acronym>
</CasingExceptions>
</Acronyms>
</Dictionary>

Просмотреть файл

@ -0,0 +1,271 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
namespace System.Collections.Generic
{
/// <summary>
/// Helper extension methods for fast use of collections.
/// </summary>
internal static class CollectionExtensions
{
/// <summary>
/// Return a new array with the value added to the end. Slow and best suited to long lived arrays with few writes relative to reads.
/// </summary>
public static T[] AppendAndReallocate<T>(this T[] array, T value)
{
Contract.Assert(array != null);
int originalLength = array.Length;
T[] newArray = new T[originalLength + 1];
array.CopyTo(newArray, 0);
newArray[originalLength] = value;
return newArray;
}
/// <summary>
/// Return the enumerable as an Array, copying if required. Optimized for common case where it is an Array.
/// Avoid mutating the return value.
/// </summary>
public static T[] AsArray<T>(this IEnumerable<T> values)
{
Contract.Assert(values != null);
T[] array = values as T[];
if (array == null)
{
array = values.ToArray();
}
return array;
}
/// <summary>
/// Return the enumerable as a Collection of T, copying if required. Optimized for the common case where it is
/// a Collection of T and avoiding a copy if it implements IList of T. Avoid mutating the return value.
/// </summary>
public static Collection<T> AsCollection<T>(this IEnumerable<T> enumerable)
{
Contract.Assert(enumerable != null);
Collection<T> collection = enumerable as Collection<T>;
if (collection != null)
{
return collection;
}
// Check for IList so that collection can wrap it instead of copying
IList<T> list = enumerable as IList<T>;
if (list == null)
{
list = new List<T>(enumerable);
}
return new Collection<T>(list);
}
/// <summary>
/// Return the enumerable as a IList of T, copying if required. Avoid mutating the return value.
/// </summary>
public static IList<T> AsIList<T>(this IEnumerable<T> enumerable)
{
Contract.Assert(enumerable != null);
IList<T> list = enumerable as IList<T>;
if (list != null)
{
return list;
}
return new List<T>(enumerable);
}
/// <summary>
/// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of T
/// or a ListWrapperCollection of T. Avoid mutating the return value.
/// </summary>
public static List<T> AsList<T>(this IEnumerable<T> enumerable)
{
Contract.Assert(enumerable != null);
List<T> list = enumerable as List<T>;
if (list != null)
{
return list;
}
ListWrapperCollection<T> listWrapper = enumerable as ListWrapperCollection<T>;
if (listWrapper != null)
{
return listWrapper.ItemsList;
}
return new List<T>(enumerable);
}
/// <summary>
/// Remove values from the list starting at the index start.
/// </summary>
public static void RemoveFrom<T>(this List<T> list, int start)
{
Contract.Assert(list != null);
Contract.Assert(start >= 0 && start <= list.Count);
list.RemoveRange(start, list.Count - start);
}
/// <summary>
/// Return the only value from list, the type's default value if empty, or call the errorAction for 2 or more.
/// </summary>
public static T SingleDefaultOrError<T, TArg1>(this IList<T> list, Action<TArg1> errorAction, TArg1 errorArg1)
{
Contract.Assert(list != null);
Contract.Assert(errorAction != null);
switch (list.Count)
{
case 0:
return default(T);
case 1:
T value = list[0];
return value;
default:
errorAction(errorArg1);
return default(T);
}
}
/// <summary>
/// Returns a single value in list matching type TMatch if there is only one, null if there are none of type TMatch or calls the
/// errorAction with errorArg1 if there is more than one.
/// </summary>
public static TMatch SingleOfTypeDefaultOrError<TInput, TMatch, TArg1>(this IList<TInput> list, Action<TArg1> errorAction, TArg1 errorArg1) where TMatch : class
{
Contract.Assert(list != null);
Contract.Assert(errorAction != null);
TMatch result = null;
for (int i = 0; i < list.Count; i++)
{
TMatch typedValue = list[i] as TMatch;
if (typedValue != null)
{
if (result == null)
{
result = typedValue;
}
else
{
errorAction(errorArg1);
return null;
}
}
}
return result;
}
/// <summary>
/// Convert an ICollection to an array, removing null values. Fast path for case where there are no null values.
/// </summary>
public static T[] ToArrayWithoutNulls<T>(this ICollection<T> collection) where T : class
{
Contract.Assert(collection != null);
T[] result = new T[collection.Count];
int count = 0;
foreach (T value in collection)
{
if (value != null)
{
result[count] = value;
count++;
}
}
if (count == collection.Count)
{
return result;
}
else
{
T[] trimmedResult = new T[count];
Array.Copy(result, trimmedResult, count);
return trimmedResult;
}
}
/// <summary>
/// Convert the array to a Dictionary using the keySelector to extract keys from values and the specified comparer. Optimized for array input.
/// </summary>
public static Dictionary<TKey, TValue> ToDictionaryFast<TKey, TValue>(this TValue[] array, Func<TValue, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
Contract.Assert(array != null);
Contract.Assert(keySelector != null);
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(array.Length, comparer);
for (int i = 0; i < array.Length; i++)
{
TValue value = array[i];
dictionary.Add(keySelector(value), value);
}
return dictionary;
}
/// <summary>
/// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified comparer. Optimized for IList of T input with fast path for array.
/// </summary>
public static Dictionary<TKey, TValue> ToDictionaryFast<TKey, TValue>(this IList<TValue> list, Func<TValue, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
Contract.Assert(list != null);
Contract.Assert(keySelector != null);
TValue[] array = list as TValue[];
if (array != null)
{
return ToDictionaryFast(array, keySelector, comparer);
}
return ToDictionaryFastNoCheck(list, keySelector, comparer);
}
/// <summary>
/// Convert the enumerable to a Dictionary using the keySelector to extract keys from values and the specified comparer. Fast paths for array and IList of T.
/// </summary>
public static Dictionary<TKey, TValue> ToDictionaryFast<TKey, TValue>(this IEnumerable<TValue> enumerable, Func<TValue, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
Contract.Assert(enumerable != null);
Contract.Assert(keySelector != null);
TValue[] array = enumerable as TValue[];
if (array != null)
{
return ToDictionaryFast(array, keySelector, comparer);
}
IList<TValue> list = enumerable as IList<TValue>;
if (list != null)
{
return ToDictionaryFastNoCheck(list, keySelector, comparer);
}
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(comparer);
foreach (TValue value in enumerable)
{
dictionary.Add(keySelector(value), value);
}
return dictionary;
}
/// <summary>
/// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified comparer. Optimized for IList of T input. No checking for other types.
/// </summary>
private static Dictionary<TKey, TValue> ToDictionaryFastNoCheck<TKey, TValue>(IList<TValue> list, Func<TValue, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
Contract.Assert(list != null);
Contract.Assert(keySelector != null);
int listCount = list.Count;
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(listCount, comparer);
for (int i = 0; i < listCount; i++)
{
TValue value = list[i];
dictionary.Add(keySelector(value), value);
}
return dictionary;
}
}
}

140
OData/src/Common/CommonWebApiResources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,140 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace System.Web.Http.Properties {
using System;
using System.Linq;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CommonWebApiResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal CommonWebApiResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
#if NETFX_CORE
var assembly = typeof(CommonWebApiResources).GetTypeInfo().Assembly;
#else
var assembly = typeof(CommonWebApiResources).Assembly;
#endif
// Find the CommonResources.resources file's full resource name in this assembly
string commonResourcesName = assembly.GetManifestResourceNames().Where(s => s.EndsWith("CommonWebApiResources.resources", StringComparison.OrdinalIgnoreCase)).Single();
// Trim off the ".resources"
commonResourcesName = commonResourcesName.Substring(0, commonResourcesName.Length - 10);
// Load the resource manager
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(commonResourcesName, assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Relative URI values are not supported: &apos;{0}&apos;. The URI must be absolute..
/// </summary>
internal static string ArgumentInvalidAbsoluteUri {
get {
return ResourceManager.GetString("ArgumentInvalidAbsoluteUri", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unsupported URI scheme: &apos;{0}&apos;. The URI scheme must be either &apos;{1}&apos; or &apos;{2}&apos;..
/// </summary>
internal static string ArgumentInvalidHttpUriScheme {
get {
return ResourceManager.GetString("ArgumentInvalidHttpUriScheme", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Value must be greater than or equal to {0}..
/// </summary>
internal static string ArgumentMustBeGreaterThanOrEqualTo {
get {
return ResourceManager.GetString("ArgumentMustBeGreaterThanOrEqualTo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Value must be less than or equal to {0}..
/// </summary>
internal static string ArgumentMustBeLessThanOrEqualTo {
get {
return ResourceManager.GetString("ArgumentMustBeLessThanOrEqualTo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The argument &apos;{0}&apos; is null or empty..
/// </summary>
internal static string ArgumentNullOrEmpty {
get {
return ResourceManager.GetString("ArgumentNullOrEmpty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to URI must not contain a query component or a fragment identifier..
/// </summary>
internal static string ArgumentUriHasQueryOrFragment {
get {
return ResourceManager.GetString("ArgumentUriHasQueryOrFragment", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The value of argument &apos;{0}&apos; ({1}) is invalid for Enum type &apos;{2}&apos;..
/// </summary>
internal static string InvalidEnumArgument {
get {
return ResourceManager.GetString("InvalidEnumArgument", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentInvalidAbsoluteUri" xml:space="preserve">
<value>Relative URI values are not supported: '{0}'. The URI must be absolute.</value>
</data>
<data name="ArgumentInvalidHttpUriScheme" xml:space="preserve">
<value>Unsupported URI scheme: '{0}'. The URI scheme must be either '{1}' or '{2}'.</value>
</data>
<data name="ArgumentMustBeGreaterThanOrEqualTo" xml:space="preserve">
<value>Value must be greater than or equal to {0}.</value>
</data>
<data name="ArgumentMustBeLessThanOrEqualTo" xml:space="preserve">
<value>Value must be less than or equal to {0}.</value>
</data>
<data name="ArgumentNullOrEmpty" xml:space="preserve">
<value>The argument '{0}' is null or empty.</value>
</data>
<data name="ArgumentUriHasQueryOrFragment" xml:space="preserve">
<value>URI must not contain a query component or a fragment identifier.</value>
</data>
<data name="InvalidEnumArgument" xml:space="preserve">
<value>The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.</value>
</data>
</root>

268
OData/src/Common/Error.cs Normal file
Просмотреть файл

@ -0,0 +1,268 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Web.Http.Properties;
namespace System.Web.Http
{
/// <summary>
/// Utility class for creating and unwrapping <see cref="Exception"/> instances.
/// </summary>
internal static class Error
{
private const string HttpScheme = "http";
private const string HttpsScheme = "https";
/// <summary>
/// Formats the specified resource string using <see cref="M:CultureInfo.CurrentCulture"/>.
/// </summary>
/// <param name="format">A composite format string.</param>
/// <param name="args">An object array that contains zero or more objects to format.</param>
/// <returns>The formatted string.</returns>
internal static string Format(string format, params object[] args)
{
return String.Format(CultureInfo.CurrentCulture, format, args);
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with the provided properties.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException Argument(string messageFormat, params object[] messageArgs)
{
return new ArgumentException(Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with the provided properties.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException Argument(string parameterName, string messageFormat, params object[] messageArgs)
{
return new ArgumentException(Error.Format(messageFormat, messageArgs), parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with a message saying that the argument must be an "http" or "https" URI.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException ArgumentUriNotHttpOrHttpsScheme(string parameterName, Uri actualValue)
{
return new ArgumentException(Error.Format(CommonWebApiResources.ArgumentInvalidHttpUriScheme, actualValue, HttpScheme, HttpsScheme), parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with a message saying that the argument must be an absolute URI.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException ArgumentUriNotAbsolute(string parameterName, Uri actualValue)
{
return new ArgumentException(Error.Format(CommonWebApiResources.ArgumentInvalidAbsoluteUri, actualValue), parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with a message saying that the argument must be an absolute URI
/// without a query or fragment identifier and then logs it with <see cref="F:TraceLevel.Error"/>.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException ArgumentUriHasQueryOrFragment(string parameterName, Uri actualValue)
{
return new ArgumentException(Error.Format(CommonWebApiResources.ArgumentUriHasQueryOrFragment, actualValue), parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentNullException"/> with the provided properties.
/// </summary>
/// <returns>The logged <see cref="Exception"/>.</returns>
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "The purpose of this API is to return an error for properties")]
internal static ArgumentNullException PropertyNull()
{
return new ArgumentNullException("value");
}
/// <summary>
/// Creates an <see cref="ArgumentNullException"/> with the provided properties.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentNullException ArgumentNull(string parameterName)
{
return new ArgumentNullException(parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentNullException"/> with the provided properties.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentNullException ArgumentNull(string parameterName, string messageFormat, params object[] messageArgs)
{
return new ArgumentNullException(parameterName, Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> with a default message.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException ArgumentNullOrEmpty(string parameterName)
{
return Error.Argument(parameterName, CommonWebApiResources.ArgumentNullOrEmpty, parameterName);
}
/// <summary>
/// Creates an <see cref="ArgumentOutOfRangeException"/> with the provided properties.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentOutOfRangeException ArgumentOutOfRange(string parameterName, object actualValue, string messageFormat, params object[] messageArgs)
{
return new ArgumentOutOfRangeException(parameterName, actualValue, Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="ArgumentOutOfRangeException"/> with a message saying that the argument must be greater than or equal to <paramref name="minValue"/>.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <param name="minValue">The minimum size of the argument.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentOutOfRangeException ArgumentMustBeGreaterThanOrEqualTo(string parameterName, object actualValue, object minValue)
{
return new ArgumentOutOfRangeException(parameterName, actualValue, Error.Format(CommonWebApiResources.ArgumentMustBeGreaterThanOrEqualTo, minValue));
}
/// <summary>
/// Creates an <see cref="ArgumentOutOfRangeException"/> with a message saying that the argument must be less than or equal to <paramref name="maxValue"/>.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="actualValue">The value of the argument that causes this exception.</param>
/// <param name="maxValue">The maximum size of the argument.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentOutOfRangeException ArgumentMustBeLessThanOrEqualTo(string parameterName, object actualValue, object maxValue)
{
return new ArgumentOutOfRangeException(parameterName, actualValue, Error.Format(CommonWebApiResources.ArgumentMustBeLessThanOrEqualTo, maxValue));
}
/// <summary>
/// Creates an <see cref="KeyNotFoundException"/> with a message saying that the key was not found.
/// </summary>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static KeyNotFoundException KeyNotFound()
{
return new KeyNotFoundException();
}
/// <summary>
/// Creates an <see cref="KeyNotFoundException"/> with a message saying that the key was not found.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static KeyNotFoundException KeyNotFound(string messageFormat, params object[] messageArgs)
{
return new KeyNotFoundException(Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="ObjectDisposedException"/> initialized according to guidelines.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ObjectDisposedException ObjectDisposed(string messageFormat, params object[] messageArgs)
{
// Pass in null, not disposedObject.GetType().FullName as per the above guideline
return new ObjectDisposedException(null, Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="OperationCanceledException"/> initialized with the provided parameters.
/// </summary>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static OperationCanceledException OperationCanceled()
{
return new OperationCanceledException();
}
/// <summary>
/// Creates an <see cref="OperationCanceledException"/> initialized with the provided parameters.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static OperationCanceledException OperationCanceled(string messageFormat, params object[] messageArgs)
{
return new OperationCanceledException(Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="ArgumentException"/> for an invalid enum argument.
/// </summary>
/// <param name="parameterName">The name of the parameter that caused the current exception.</param>
/// <param name="invalidValue">The value of the argument that failed.</param>
/// <param name="enumClass">A <see cref="Type"/> that represents the enumeration class with the valid values.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static ArgumentException InvalidEnumArgument(string parameterName, int invalidValue, Type enumClass)
{
#if NETFX_CORE
return new ArgumentException(Error.Format(CommonWebApiResources.InvalidEnumArgument, parameterName, invalidValue, enumClass.Name), parameterName);
#else
return new InvalidEnumArgumentException(parameterName, invalidValue, enumClass);
#endif
}
/// <summary>
/// Creates an <see cref="InvalidOperationException"/>.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static InvalidOperationException InvalidOperation(string messageFormat, params object[] messageArgs)
{
return new InvalidOperationException(Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="InvalidOperationException"/>.
/// </summary>
/// <param name="innerException">Inner exception</param>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static InvalidOperationException InvalidOperation(Exception innerException, string messageFormat, params object[] messageArgs)
{
return new InvalidOperationException(Error.Format(messageFormat, messageArgs), innerException);
}
/// <summary>
/// Creates an <see cref="NotSupportedException"/>.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static NotSupportedException NotSupported(string messageFormat, params object[] messageArgs)
{
return new NotSupportedException(Error.Format(messageFormat, messageArgs));
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
namespace System.Collections.ObjectModel
{
/// <summary>
/// A class that inherits from Collection of T but also exposes its underlying data as List of T for performance.
/// </summary>
internal sealed class ListWrapperCollection<T> : Collection<T>
{
private readonly List<T> _items;
internal ListWrapperCollection()
: this(new List<T>())
{
}
internal ListWrapperCollection(List<T> list)
: base(list)
{
_items = list;
}
internal List<T> ItemsList
{
get { return _items; }
}
}
}

Просмотреть файл

@ -0,0 +1,190 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;
#if ASPNETWEBAPI
namespace System.Web.Http.Internal
#else
namespace System.Web.WebPages
#endif
{
internal class PropertyHelper
{
private static ConcurrentDictionary<Type, PropertyHelper[]> _reflectionCache = new ConcurrentDictionary<Type, PropertyHelper[]>();
private Func<object, object> _valueGetter;
/// <summary>
/// Initializes a fast property helper. This constructor does not cache the helper.
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "This is intended the Name is auto set differently per type and the type is internal")]
public PropertyHelper(PropertyInfo property)
{
Contract.Assert(property != null);
Name = property.Name;
_valueGetter = MakeFastPropertyGetter(property);
}
/// <summary>
/// Creates a single fast property setter. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
/// <returns>a fast setter.</returns>
/// <remarks>This method is more memory efficient than a dynamically compiled lambda, and about the same speed.</remarks>
public static Action<TDeclaringType, object> MakeFastPropertySetter<TDeclaringType>(PropertyInfo propertyInfo)
where TDeclaringType : class
{
Contract.Assert(propertyInfo != null);
MethodInfo setMethod = propertyInfo.GetSetMethod();
Contract.Assert(setMethod != null);
Contract.Assert(!setMethod.IsStatic);
Contract.Assert(setMethod.GetParameters().Length == 1);
Contract.Assert(!propertyInfo.ReflectedType.IsValueType);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "this". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
Type typeInput = propertyInfo.ReflectedType;
Type typeValue = setMethod.GetParameters()[0].ParameterType;
Delegate callPropertySetterDelegate;
// Create a delegate TValue -> "TDeclaringType.Property"
var propertySetterAsAction = setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, typeValue));
var callPropertySetterClosedGenericMethod = _callPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, typeValue);
callPropertySetterDelegate = Delegate.CreateDelegate(typeof(Action<TDeclaringType, object>), propertySetterAsAction, callPropertySetterClosedGenericMethod);
return (Action<TDeclaringType, object>)callPropertySetterDelegate;
}
public virtual string Name { get; protected set; }
public object GetValue(object instance)
{
Contract.Assert(_valueGetter != null, "Must call Initialize before using this object");
return _valueGetter(instance);
}
/// <summary>
/// Creates and caches fast property helpers that expose getters for every public get property on the underlying type.
/// </summary>
/// <param name="instance">the instance to extract property accessors for.</param>
/// <returns>a cached array of all public property getters from the underlying type of this instance.</returns>
public static PropertyHelper[] GetProperties(object instance)
{
return GetProperties(instance, CreateInstance, _reflectionCache);
}
/// <summary>
/// Creates a single fast property getter. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>This method is more memory efficient than a dynamically compiled lambda, and about the same speed.</remarks>
public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
{
Contract.Assert(propertyInfo != null);
MethodInfo getMethod = propertyInfo.GetGetMethod();
Contract.Assert(getMethod != null);
Contract.Assert(!getMethod.IsStatic);
Contract.Assert(getMethod.GetParameters().Length == 0);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "this". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
Type typeInput = getMethod.ReflectedType;
Type typeOutput = getMethod.ReturnType;
Delegate callPropertyGetterDelegate;
if (typeInput.IsValueType)
{
// Create a delegate (ref TDeclaringType) -> TValue
Delegate propertyGetterAsFunc = getMethod.CreateDelegate(typeof(ByRefFunc<,>).MakeGenericType(typeInput, typeOutput));
MethodInfo callPropertyGetterClosedGenericMethod = _callPropertyGetterByReferenceOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
callPropertyGetterDelegate = Delegate.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc, callPropertyGetterClosedGenericMethod);
}
else
{
// Create a delegate TDeclaringType -> TValue
Delegate propertyGetterAsFunc = getMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(typeInput, typeOutput));
MethodInfo callPropertyGetterClosedGenericMethod = _callPropertyGetterOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
callPropertyGetterDelegate = Delegate.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc, callPropertyGetterClosedGenericMethod);
}
return (Func<object, object>)callPropertyGetterDelegate;
}
private static PropertyHelper CreateInstance(PropertyInfo property)
{
return new PropertyHelper(property);
}
// Implementation of the fast getter.
private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);
private static readonly MethodInfo _callPropertyGetterOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertyGetter", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly MethodInfo _callPropertyGetterByReferenceOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertyGetterByReference", BindingFlags.NonPublic | BindingFlags.Static);
private static object CallPropertyGetter<TDeclaringType, TValue>(Func<TDeclaringType, TValue> getter, object @this)
{
return getter((TDeclaringType)@this);
}
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(ByRefFunc<TDeclaringType, TValue> getter, object @this)
{
TDeclaringType unboxed = (TDeclaringType)@this;
return getter(ref unboxed);
}
// Implementation of the fast setter.
private static readonly MethodInfo _callPropertySetterOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertySetter", BindingFlags.NonPublic | BindingFlags.Static);
private static void CallPropertySetter<TDeclaringType, TValue>(Action<TDeclaringType, TValue> setter, object @this, object value)
{
setter((TDeclaringType)@this, (TValue)value);
}
protected static PropertyHelper[] GetProperties(object instance,
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
ConcurrentDictionary<Type, PropertyHelper[]> cache)
{
// Using an array rather than IEnumerable, as this will be called on the hot path numerous times.
PropertyHelper[] helpers;
Type type = instance.GetType();
if (!cache.TryGetValue(type, out helpers))
{
// We avoid loading indexed properties using the where statement.
// Indexed properties are not useful (or valid) for grabbing properties off an anonymous object.
IEnumerable<PropertyInfo> properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(prop => prop.GetIndexParameters().Length == 0 &&
prop.GetMethod != null);
var newHelpers = new List<PropertyHelper>();
foreach (PropertyInfo property in properties)
{
PropertyHelper propertyHelper = createPropertyHelper(property);
newHelpers.Add(propertyHelper);
}
helpers = newHelpers.ToArray();
cache.TryAdd(type, helpers);
}
return helpers;
}
}
}

Просмотреть файл

@ -0,0 +1,84 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace System.Threading.Tasks
{
/// <summary>
/// Helpers for safely using Task libraries.
/// </summary>
internal static class TaskHelpers
{
private static readonly Task _defaultCompleted = Task.FromResult<AsyncVoid>(default(AsyncVoid));
private static readonly Task<object> _completedTaskReturningNull = Task.FromResult<object>(null);
/// <summary>
/// Returns a canceled Task. The task is completed, IsCanceled = True, IsFaulted = False.
/// </summary>
internal static Task Canceled()
{
return CancelCache<AsyncVoid>.Canceled;
}
/// <summary>
/// Returns a canceled Task of the given type. The task is completed, IsCanceled = True, IsFaulted = False.
/// </summary>
internal static Task<TResult> Canceled<TResult>()
{
return CancelCache<TResult>.Canceled;
}
/// <summary>
/// Returns a completed task that has no result.
/// </summary>
internal static Task Completed()
{
return _defaultCompleted;
}
/// <summary>
/// Returns an error task. The task is Completed, IsCanceled = False, IsFaulted = True
/// </summary>
internal static Task FromError(Exception exception)
{
return FromError<AsyncVoid>(exception);
}
/// <summary>
/// Returns an error task of the given type. The task is Completed, IsCanceled = False, IsFaulted = True
/// </summary>
/// <typeparam name="TResult"></typeparam>
internal static Task<TResult> FromError<TResult>(Exception exception)
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
tcs.SetException(exception);
return tcs.Task;
}
internal static Task<object> NullResult()
{
return _completedTaskReturningNull;
}
/// <summary>
/// Used as the T in a "conversion" of a Task into a Task{T}
/// </summary>
private struct AsyncVoid
{
}
/// <summary>
/// This class is a convenient cache for per-type cancelled tasks
/// </summary>
private static class CancelCache<TResult>
{
public static readonly Task<TResult> Canceled = GetCancelledTask();
private static Task<TResult> GetCancelledTask()
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
tcs.SetCanceled();
return tcs.Task;
}
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
namespace System.Threading.Tasks
{
internal static class TaskHelpersExtensions
{
/// <summary>
/// Cast Task to Task of object
/// </summary>
internal static async Task<object> CastToObject(this Task task)
{
await task;
return null;
}
/// <summary>
/// Cast Task of T to Task of object
/// </summary>
internal static async Task<object> CastToObject<T>(this Task<T> task)
{
return (object)await task;
}
/// <summary>
/// Throws the first faulting exception for a task which is faulted. It preserves the original stack trace when
/// throwing the exception. Note: It is the caller's responsibility not to pass incomplete tasks to this
/// method, because it does degenerate into a call to the equivalent of .Wait() on the task when it hasn't yet
/// completed.
/// </summary>
internal static void ThrowIfFaulted(this Task task)
{
task.GetAwaiter().GetResult();
}
/// <summary>
/// Attempts to get the result value for the given task. If the task ran to completion, then
/// it will return true and set the result value; otherwise, it will return false.
/// </summary>
[SuppressMessage("Microsoft.Web.FxCop", "MW1201:DoNotCallProblematicMethodsOnTask", Justification = "The usages here are deemed safe, and provide the implementations that this rule relies upon.")]
internal static bool TryGetResult<TResult>(this Task<TResult> task, out TResult result)
{
if (task.Status == TaskStatus.RanToCompletion)
{
result = task.Result;
return true;
}
result = default(TResult);
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
namespace System
{
/// <summary>
/// Extension methods for <see cref="Type"/>.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class TypeExtensions
{
public static bool IsNullable(this Type type)
{
if (type.IsValueType)
{
// value types are only nullable if they are Nullable<T>
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
else
{
// reference types are always nullable
return true;
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
#if !BUILD_GENERATED_VERSION
[assembly: AssemblyCompany("Microsoft Open Technologies, Inc.")]
[assembly: AssemblyCopyright("© Microsoft Open Technologies, Inc. All rights reserved.")]
#endif
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
#if !NOT_CLS_COMPLIANT
[assembly: CLSCompliant(true)]
#endif
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyMetadata("Serviceable", "True")]
// ===========================================================================
// DO NOT EDIT OR REMOVE ANYTHING BELOW THIS COMMENT.
// Version numbers are automatically generated based on regular expressions.
// ===========================================================================
#if ASPNETODATA
#if !BUILD_GENERATED_VERSION
[assembly: AssemblyVersion("5.3.0.0")] // ASPNETODATA
[assembly: AssemblyFileVersion("5.3.0.0")] // ASPNETODATA
#endif
[assembly: AssemblyProduct("Microsoft ASP.NET Web API OData")]
#endif

Просмотреть файл

@ -0,0 +1,5 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification = "Assembly is delay-signed")]

Просмотреть файл

@ -0,0 +1,5 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<StringProperty Name="MergeSettingsFiles">Parent</StringProperty>
</GlobalSettings>
</StyleCopSettings>

11
OData/src/Strict.ruleset Normal file
Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="FxCop rules for ASP.NET Web Stack" Description="This rule set contains the rules for ASP.NET Web Stack." ToolsVersion="10.0">
<RuleHintPaths>
<Path>..\packages\CustomFxCopRules</Path>
</RuleHintPaths>
<IncludeAll Action="Error" />
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1062" Action="None" />
<Rule Id="MW1200" Action="None" />
</Rules>
</RuleSet>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebApiOData.sln))\tools\WebStack.settings.targets" />
<PropertyGroup>
<ProjectGuid>{CF73AAA7-ACE9-4C91-AFA5-5EC1DF18FEEE}</ProjectGuid>
<OutputType>Library</OutputType>
@ -9,7 +9,7 @@
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETMVC;ASPNETWEBAPI</DefineConstants>
<DefineConstants>$(DefineConstants);ASPNETODATA;ASPNETWEBAPI</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Data.Edm, Version=5.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@ -29,12 +29,20 @@
<Reference Include="System.Core" />
<Reference Include="System.Data.Linq" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.0\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Spatial, Version=5.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\System.Spatial.5.6.0\lib\net40\System.Spatial.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.0\lib\net45\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
@ -359,16 +367,6 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Net.Http.Formatting\System.Net.Http.Formatting.csproj">
<Project>{668e9021-ce84-49d9-98fb-df125a9fcdb0}</Project>
<Name>System.Net.Http.Formatting</Name>
</ProjectReference>
<ProjectReference Include="..\System.Web.Http\System.Web.Http.csproj">
<Project>{ddc1ce0c-486e-4e35-bb3b-eab61f8f9440}</Project>
<Name>System.Web.Http</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net45" />
<package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),Runtime.sln))\tools\WebStack.settings.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebApiOData.sln))\tools\WebStack.settings.targets" />
<PropertyGroup>
<ProjectGuid>{D23E28F1-CCD0-43E0-8C0D-36731EC91318}</ProjectGuid>
<OutputType>Library</OutputType>
@ -9,7 +9,7 @@
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<RunCodeAnalysis>$(CodeAnalysis)</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>
<DefineConstants>$(DefineConstants);ASPNETMVC;ASPNETWEBAPI</DefineConstants>
<DefineConstants>$(DefineConstants);ASPNETODATA;ASPNETWEBAPI</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Core, Version=6.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@ -33,8 +33,16 @@
<Reference Include="System.Core" />
<Reference Include="System.Data.Linq" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.0\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web.Http, Version=5.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.0\lib\net45\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
@ -424,16 +432,6 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.Net.Http.Formatting\System.Net.Http.Formatting.csproj">
<Project>{668e9021-ce84-49d9-98fb-df125a9fcdb0}</Project>
<Name>System.Net.Http.Formatting</Name>
</ProjectReference>
<ProjectReference Include="..\System.Web.Http\System.Web.Http.csproj">
<Project>{ddc1ce0c-486e-4e35-bb3b-eab61f8f9440}</Project>
<Name>System.Web.Http</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.OData.Core" version="6.5.0" targetFramework="net45" />
<package id="Microsoft.OData.Edm" version="6.5.0" targetFramework="net45" />
<package id="Microsoft.Spatial" version="6.5.0" targetFramework="net45" />

Просмотреть файл

@ -0,0 +1,128 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Generic;
using Microsoft.TestCommon;
namespace System.ComponentModel
{
public class AttributeListTest
{
private readonly Attribute[] _testAttributes;
private readonly AttributeCollection _collection;
private readonly AttributeList _list;
public AttributeListTest()
{
_testAttributes = new Attribute[] { new TestAttribute(), new DerivedAttribute(), new DerivedDerivedAttribute() };
_collection = new AttributeCollection(_testAttributes);
_list = new AttributeList(_collection);
}
[Fact]
public void AttributeListCountMatchesWrapped()
{
Assert.Equal(_collection.Count, _list.Count);
}
[Fact]
public void AttributeListIsReadOnlyTrue()
{
Assert.True(_list.IsReadOnly);
}
[Fact]
public void AttributeListIndexerMatchesWrapped()
{
Assert.Equal(_collection[1], _list[1]);
}
[Fact]
public void AttributeListAddThrows()
{
Assert.Throws<NotSupportedException>(() => _list.Add(null));
}
[Fact]
public void AttributeListClearThrows()
{
Assert.Throws<NotSupportedException>(() => _list.Clear());
}
[Fact]
public void AttributeListContainsWrappedTrue()
{
Attribute presentAttribute = _collection[2];
Assert.True(_list.Contains(presentAttribute));
}
[Fact]
public void AttributeListContainsMissingFalse()
{
Attribute missingAttribute = new MissingAttribute();
Assert.False(_list.Contains(missingAttribute));
}
[Fact]
public void AttributeListCopyToResultsEqual()
{
Attribute[] arrayCopy = new Attribute[3];
_list.CopyTo(arrayCopy, 0);
Assert.Equal(_list, arrayCopy);
}
[Fact]
public void AttributeListIndexOfMatchesIndexer()
{
Assert.Equal(1, _list.IndexOf(_list[1]));
}
[Fact]
public void AttributeListRemoveAtThrows()
{
Assert.Throws<NotSupportedException>(() => _list.RemoveAt(0));
Assert.Throws<NotSupportedException>(() => ((ICollection<Attribute>)_list).Remove(_list[0]));
}
[Fact]
public void AttributeListEnumerationMatchesWrapped()
{
int i = 0;
foreach (Attribute attribute in _list)
{
Assert.Equal(_collection[i], attribute);
i++;
}
Assert.Equal(_collection.Count, i);
i = 0;
IEnumerable asEumerable = _list as IEnumerable;
foreach (Attribute attribute in asEumerable)
{
Assert.Equal(_collection[i], attribute);
i++;
}
Assert.Equal(_collection.Count, i);
}
private class TestAttribute : Attribute
{
public TestAttribute() { }
}
private class DerivedAttribute: TestAttribute
{
public DerivedAttribute() { }
}
private class DerivedDerivedAttribute : DerivedAttribute
{
public DerivedDerivedAttribute() { }
}
private class MissingAttribute : Attribute
{
public MissingAttribute() { }
}
}
}

Просмотреть файл

@ -0,0 +1,354 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.TestCommon;
namespace System.Collections.Generic
{
public class CollectionExtensionsTest
{
[Fact]
public void AppendAndReallocateEmpty_ReturnsOne()
{
string[] empty = new string[0];
string[] emptyAppended = empty.AppendAndReallocate("AppendedEmpty");
Assert.Equal(1, emptyAppended.Length);
Assert.Equal("AppendedEmpty", emptyAppended[0]);
}
[Fact]
public void AppendAndReallocateOne_ReturnsTwo()
{
string[] one = new string[] { "One" };
string[] oneAppended = one.AppendAndReallocate("AppendedOne");
Assert.Equal(2, oneAppended.Length);
Assert.Equal("One", oneAppended[0]);
Assert.Equal("AppendedOne", oneAppended[1]);
}
[Fact]
public void AsArray_Array_ReturnsSameInstance()
{
object[] array = new object[] { new object(), new object() };
object[] arrayAsArray = ((IEnumerable<object>)array).AsArray();
Assert.Same(array, arrayAsArray);
}
[Fact]
public void AsArray_Enumerable_Copies()
{
IList<object> list = new List<object>() { new object(), new object() };
object[] listToArray = list.ToArray();
object[] listAsArray = ((IEnumerable<object>)list).AsArray();
Assert.Equal(listToArray, listAsArray);
}
[Fact]
public void AsCollection_Collection_ReturnsSameInstance()
{
Collection<object> collection = new Collection<object>() { new object(), new object() };
Collection<object> collectionAsCollection = ((IEnumerable<object>)collection).AsCollection();
Assert.Same(collection, collectionAsCollection);
}
[Fact]
public void AsCollection_Enumerable_Copies()
{
IEnumerable<object> enumerable = new LinkedList<object>(new object[] { new object(), new object() });
Collection<object> enumerableAsCollection = ((IEnumerable<object>)enumerable).AsCollection();
Assert.Equal(enumerable, ((IEnumerable<object>)enumerableAsCollection));
}
[Fact]
public void AsCollection_IList_Wraps()
{
IList<object> list = new List<object>() { new object(), new object() };
Collection<object> listAsCollection = list.AsCollection();
list.Add(new object());
Assert.Equal(list, listAsCollection.ToList());
}
[Fact]
public void AsIList_IList_ReturnsSameInstance()
{
List<object> list = new List<object> { new object(), new object() };
IList<object> listAsIList = ((IEnumerable<object>)list).AsIList();
Assert.Same(list, listAsIList);
}
[Fact]
public void AsIList_Enumerable_Copies()
{
LinkedList<object> enumerable = new LinkedList<object>();
enumerable.AddLast(new object());
enumerable.AddLast(new object());
List<object> expected = enumerable.ToList();
IList<object> enumerableAsIList = ((IEnumerable<object>)enumerable).AsIList();
Assert.Equal(expected, enumerableAsIList);
Assert.NotSame(expected, enumerableAsIList);
}
[Fact]
public void AsList_List_ReturnsSameInstance()
{
List<object> list = new List<object> { new object(), new object() };
List<object> listAsList = ((IEnumerable<object>)list).AsList();
Assert.Same(list, listAsList);
}
[Fact]
public void AsList_Enumerable_Copies()
{
List<object> list = new List<object>() { new object(), new object() };
object[] array = list.ToArray();
List<object> arrayAsList = ((IEnumerable<object>)array).AsList();
Assert.Equal(list, arrayAsList);
Assert.NotSame(list, arrayAsList);
Assert.NotSame(array, arrayAsList);
}
public void AsList_ListWrapperCollection_ReturnsSameInstance()
{
List<object> list = new List<object> { new object(), new object() };
ListWrapperCollection<object> listWrapper = new ListWrapperCollection<object>(list);
List<object> listWrapperAsList = ((IEnumerable<object>)listWrapper).AsList();
Assert.Same(list, listWrapperAsList);
}
[Fact]
void RemoveFromTwoElementsAtEnd_NoChange()
{
List<object> list = new List<object>() { new object(), new object() };
List<object> listExpected = new List<object>(list);
list.RemoveFrom(2);
Assert.Equal(listExpected, list);
}
[Fact]
void RemoveFromTwoElementsMiddle_ToOne()
{
List<object> list = new List<object>() { new object(), new object() };
List<object> listExpected = new List<object>() { list[0] };
list.RemoveFrom(1);
Assert.Equal(listExpected, list);
}
[Fact]
void RemoveFromTwoElementsStart_ToEmpty()
{
List<object> list = new List<object>() { new object(), new object() };
List<object> listExpected = new List<object>();
list.RemoveFrom(0);
Assert.Equal(listExpected, list);
}
[Fact]
void SingleDefaultOrErrorIListEmptyReturnsNull()
{
IList<object> empty = new List<object>();
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
throw new InvalidOperationException();
};
Assert.Null(empty.SingleDefaultOrError(errorAction, errorArgument));
}
[Fact]
public void SingleDefaultOrErrorIListSingleReturns()
{
IList<object> single = new List<object>() { new object() };
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
throw new InvalidOperationException();
};
Assert.Equal(single[0], single.SingleDefaultOrError(errorAction, errorArgument));
}
[Fact]
public void SingleDefaultOrErrorIListMultipleThrows()
{
IList<object> multiple = new List<object>() { new object(), new object() };
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
Assert.Equal(errorArgument, argument);
throw new InvalidOperationException();
};
Assert.Throws<InvalidOperationException>(() => multiple.SingleDefaultOrError(errorAction, errorArgument));
}
[Fact]
public void SingleOfTypeDefaultOrErrorIListNoMatchReturnsNull()
{
IList<object> noMatch = new List<object>() { new object(), new object() };
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
throw new InvalidOperationException();
};
Assert.Null(noMatch.SingleOfTypeDefaultOrError<object, string, object>(errorAction, errorArgument));
}
[Fact]
public void SingleOfTypeDefaultOrErrorIListOneMatchReturns()
{
IList<object> singleMatch = new List<object>() { new object(), "Match", new object() };
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
throw new InvalidOperationException();
};
Assert.Equal("Match", singleMatch.SingleOfTypeDefaultOrError<object, string, object>(errorAction, errorArgument));
}
[Fact]
public void SingleOfTypeDefaultOrErrorIListMultipleMatchesThrows()
{
IList<object> multipleMatch = new List<object>() { new object(), "Match1", new object(), "Match2" };
object errorArgument = new object();
Action<object> errorAction = (object argument) =>
{
Assert.Equal(errorArgument, argument);
throw new InvalidOperationException();
};
Assert.Throws<InvalidOperationException>(() => multipleMatch.SingleOfTypeDefaultOrError<object, string, object>(errorAction, errorArgument));
}
[Fact]
public void ToArrayWithoutNullsICollectionNoNullsCopies()
{
ICollection<object> noNulls = new object[] { new object(), new object() };
object[] noNullsresult = noNulls.ToArrayWithoutNulls();
Assert.Equal(noNulls, noNullsresult);
}
[Fact]
public void ToArrayWithoutNullsICollectionHasNullsRemovesNulls()
{
IList<object> hasNulls = new List<object>() { new object(), null, new object() };
object[] hasNullsResult = ((ICollection<object>)hasNulls).ToArrayWithoutNulls();
Assert.Equal(2, hasNullsResult.Length);
Assert.Equal(hasNulls[0], hasNullsResult[0]);
Assert.Equal(hasNulls[2], hasNullsResult[1]);
}
[Fact]
public void ToDictionaryFastArray2Element()
{
string[] input = new string[] {"AA", "BB"};
var expectedOutput = new Dictionary<string, string>() { { "A", "AA"}, {"B", "BB"}};
Func<string, string> keySelector = (string value) => value.Substring(1);
var result = input.ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, result);
Assert.Equal(StringComparer.OrdinalIgnoreCase, result.Comparer);
}
[Fact]
public void ToDictionaryFastIListList2Element()
{
string[] input = new string[] {"AA", "BB"};
var expectedOutput = new Dictionary<string, string>() { { "A", "AA"}, {"B", "BB"}};
Func<string, string> keySelector = (string value) => value.Substring(1);
List<string> listInput = new List<string>(input);
var listResult = listInput.ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, listResult);
Assert.Equal(StringComparer.OrdinalIgnoreCase, listResult.Comparer);
}
[Fact]
public void ToDictionaryFastIListArray2Element()
{
string[] input = new string[] { "AA", "BB" };
var expectedOutput = new Dictionary<string, string>() { { "A", "AA" }, { "B", "BB" } };
Func<string, string> keySelector = (string value) => value.Substring(1);
IList<string> arrayAsList = input;
var arrayResult = arrayAsList.ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, arrayResult);
Assert.Equal(StringComparer.OrdinalIgnoreCase, arrayResult.Comparer);
}
[Fact]
public void ToDictionaryFastIEnumerableArray2Element()
{
string[] input = new string[] {"AA", "BB"};
var expectedOutput = new Dictionary<string, string>() { { "A", "AA"}, {"B", "BB"}};
Func<string, string> keySelector = (string value) => value.Substring(1);
var arrayResult = ((IEnumerable<string>)input).ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, arrayResult);
Assert.Equal(StringComparer.OrdinalIgnoreCase, arrayResult.Comparer);
}
[Fact]
public void ToDictionaryFastIEnumerableList2Element()
{
string[] input = new string[] { "AA", "BB" };
var expectedOutput = new Dictionary<string, string>() { { "A", "AA" }, { "B", "BB" } };
Func<string, string> keySelector = (string value) => value.Substring(1);
List<string> listInput = new List<string>(input);
var listResult = ((IEnumerable<string>)listInput).ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, listResult);
Assert.Equal(StringComparer.OrdinalIgnoreCase, listResult.Comparer);
}
[Fact]
public void ToDictionaryFastIEnumerableLinkedList2Element()
{
string[] input = new string[] { "AA", "BB" };
var expectedOutput = new Dictionary<string, string>() { { "A", "AA" }, { "B", "BB" } };
Func<string, string> keySelector = (string value) => value.Substring(1);
LinkedList<string> linkedListInput = new LinkedList<string>(input);
var enumerableResult = ((IEnumerable<string>)linkedListInput).ToDictionaryFast(keySelector, StringComparer.OrdinalIgnoreCase);
Assert.Equal(expectedOutput, enumerableResult);
Assert.Equal(StringComparer.OrdinalIgnoreCase, enumerableResult.Comparer);
}
}
}

Просмотреть файл

@ -0,0 +1,161 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.TestCommon;
namespace System.Collections.Generic
{
public class DictionaryExtensionsTest
{
public static TheoryDataSet<object> DictionaryValues
{
get
{
return new TheoryDataSet<object>
{
"test",
new string[] { "A", "B", "C" },
8,
new List<int> {1, 2, 3},
1D,
(IEnumerable<double>)new List<double> { 1D, 2D, 3D },
new Uri("http://some.host"),
Guid.NewGuid(),
HttpStatusCode.NotImplemented,
new HttpStatusCode[] { HttpStatusCode.Accepted, HttpStatusCode.Ambiguous, HttpStatusCode.BadGateway }
};
}
}
[Fact]
public void IsCorrectType()
{
Assert.Type.HasProperties(typeof(DictionaryExtensions), TypeAssert.TypeProperties.IsStatic | TypeAssert.TypeProperties.IsClass);
}
[Fact]
public void RemoveFromDictionary_Args0_EvensRemoved()
{
Dictionary<object, int> dictionary = new Dictionary<object, int>();
object object1 = new object();
object object2 = new object();
object object3 = new object();
object object4 = new object();
dictionary.Add(object1, 1);
dictionary.Add(object2, 2);
dictionary.Add(object3, 3);
dictionary.Add(object4, 4);
Func<KeyValuePair<object, int>, bool> removeAction = (KeyValuePair<object, int> entry) =>
{
// remove even values
return (entry.Value % 2) == 0;
};
dictionary.RemoveFromDictionary(removeAction);
Assert.Equal(2, dictionary.Count);
Assert.True(dictionary.ContainsKey(object1));
Assert.False(dictionary.ContainsKey(object2));
Assert.True(dictionary.ContainsKey(object3));
Assert.False(dictionary.ContainsKey(object4));
}
[Fact]
public void RemoveFromDictionary_Args1_EvensRemoved()
{
Dictionary<object, int> dictionary = new Dictionary<object, int>();
object object1 = new object();
object object2 = new object();
object object3 = new object();
object object4 = new object();
dictionary.Add(object1, 1);
dictionary.Add(object2, 2);
dictionary.Add(object3, 3);
dictionary.Add(object4, 4);
object expectedArgument = new object();
Func<KeyValuePair<object, int>, object, bool> removeAction = (KeyValuePair<object, int> entry, object arg) =>
{
Assert.Equal(expectedArgument, arg);
// remove even values
return (entry.Value % 2) == 0;
};
dictionary.RemoveFromDictionary(removeAction, expectedArgument);
Assert.Equal(2, dictionary.Count);
Assert.True(dictionary.ContainsKey(object1));
Assert.False(dictionary.ContainsKey(object2));
Assert.True(dictionary.ContainsKey(object3));
Assert.False(dictionary.ContainsKey(object4));
}
[Fact]
public void TryGetValueThrowsOnNullKey()
{
IDictionary<string, object> dict = new Dictionary<string, object>();
string value;
Assert.ThrowsArgumentNull(() => dict.TryGetValue<string>(null, out value), "key");
}
[Fact]
public void TryGetValueReturnsFalse()
{
// Arrange
IDictionary<string, object> dict = new Dictionary<string, object>();
// Act
string resultValue = null;
bool result = dict.TryGetValue("notfound", out resultValue);
// Assert
Assert.False(result);
Assert.Null(resultValue);
}
[Theory]
[PropertyData("DictionaryValues")]
public void TryGetValueReturnsTrue<T>(T value)
{
// Arrange
IDictionary<string, object> dict = new Dictionary<string, object>()
{
{ "key", value }
};
// Act
T resultValue;
bool result = DictionaryExtensions.TryGetValue(dict, "key", out resultValue);
// Assert
Assert.True(result);
Assert.Equal(typeof(T), resultValue.GetType());
Assert.Equal(value, resultValue);
}
[Fact]
public void FindKeysWithPrefixRecognizesRootChilden()
{
// Arrange
IDictionary<string, int> dict = new Dictionary<string, int>()
{
{ "[0]", 1 },
{ "Name", 2 },
{ "Address.Street", 3 },
{ "", 4 }
};
// Act
List<int> results = DictionaryExtensions.FindKeysWithPrefix<int>(dict, "").Select(kvp => kvp.Value).ToList();
// Assert
Assert.Equal(4, results.Count);
Assert.Contains(1, results);
Assert.Contains(2, results);
Assert.Contains(3, results);
Assert.Contains(4, results);
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.TestCommon;
namespace System.Web.Http
{
public class ErrorTest
{
[Fact]
public void Format()
{
// Arrange
string expected = "The formatted message";
// Act
string actual = Error.Format("The {0} message", "formatted");
// Assert
Assert.Equal(expected, actual);
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using Microsoft.TestCommon;
namespace System.Web.Http
{
public class HttpMethodHelperTest
{
public static TheoryDataSet<string, HttpMethod> CommonHttpMethods
{
get
{
return new TheoryDataSet<string, HttpMethod>
{
{ "Get", HttpMethod.Get },
{ "Post", HttpMethod.Post },
{ "Put", HttpMethod.Put },
{ "Delete", HttpMethod.Delete },
{ "Head", HttpMethod.Head },
{ "Options", HttpMethod.Options },
{ "Trace", HttpMethod.Trace },
};
}
}
public static TheoryDataSet<string> UncommonHttpMethods
{
get
{
return new TheoryDataSet<string>
{
"Debug",
"Patch",
"Connect",
"Random",
"M-Get",
};
}
}
[Fact]
public void GetHttpMethod_ReturnsNullOnNullorEmpty()
{
Assert.Null(HttpMethodHelper.GetHttpMethod(null));
Assert.Null(HttpMethodHelper.GetHttpMethod(String.Empty));
}
[Theory]
[PropertyData("CommonHttpMethods")]
public void GetHttpMethod_RetunsStaticResult(string method, HttpMethod expectedMethod)
{
Assert.Same(expectedMethod, HttpMethodHelper.GetHttpMethod(method));
Assert.Same(expectedMethod, HttpMethodHelper.GetHttpMethod(method.ToLowerInvariant()));
Assert.Same(expectedMethod, HttpMethodHelper.GetHttpMethod(method.ToUpperInvariant()));
}
[Theory]
[PropertyData("UncommonHttpMethods")]
public void GetHttpMethod_RetunsNonStaticResult(string method)
{
Assert.Equal(method, HttpMethodHelper.GetHttpMethod(method).ToString());
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.TestCommon;
namespace System.Collections.ObjectModel
{
public class ListWrapperCollectionTests
{
[Fact]
public void ListWrapperCollection_ItemsList_HasSameContents()
{
// Arrange
ListWrapperCollection<object> listWrapper = new ListWrapperCollection<object>();
// Act
listWrapper.Add(new object());
listWrapper.Add(new object());
// Assert
Assert.Equal(listWrapper, listWrapper.ItemsList);
}
[Fact]
public void ListWrapperCollection_ItemsList_IsPassedInList()
{
// Arrange
List<object> list = new List<object>() { new object(), new object() };
ListWrapperCollection<object> listWrapper = new ListWrapperCollection<object>(list);
// Act & Assert
Assert.Same(list, listWrapper.ItemsList);
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Web;
using Microsoft.TestCommon;
namespace System.Web.Test
{
public class PathHelpersTest
{
[Theory]
[InlineData("foo.Bar", "bar")]
[InlineData("foo.bar", "bar")]
[InlineData(".bar", "bar")]
public void EndsWithExtensionReturnsTrue(string path, string extension)
{
Assert.True(PathHelpers.EndsWithExtension(path, extension));
}
[Theory]
[InlineData("foo.Baz", "bar")]
[InlineData("", "bar")]
[InlineData("Bar", "bar")]
[InlineData("fooBar", "bar")]
public void EndsWithExtensionReturnsFalse(string path, string extension)
{
Assert.False(PathHelpers.EndsWithExtension(path, extension));
}
}
}

Просмотреть файл

@ -0,0 +1,226 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.TestCommon;
namespace System.Web
{
[CLSCompliant(false)]
public class PrefixContainerTests
{
[Fact]
public void Constructor_GuardClauses()
{
// Act & assert
Assert.ThrowsArgumentNull(() => new PrefixContainer(null), "values");
}
[Fact]
public void ContainsPrefix_GuardClauses()
{
// Arrange
var container = new PrefixContainer(new string[0]);
// Act & assert
Assert.ThrowsArgumentNull(() => container.ContainsPrefix(null), "prefix");
}
[Fact]
public void ContainsPrefix_EmptyCollectionReturnsFalse()
{
// Arrange
var container = new PrefixContainer(new string[0]);
// Act & Assert
Assert.False(container.ContainsPrefix(""));
}
[Fact]
public void ContainsPrefix_ExactMatch()
{
// Arrange
var container = new PrefixContainer(new[] { "Hello" });
// Act & Assert
Assert.True(container.ContainsPrefix("Hello"));
}
[Fact]
public void ContainsPrefix_MatchIsCaseInsensitive()
{
// Arrange
var container = new PrefixContainer(new[] { "Hello" });
// Act & Assert
Assert.True(container.ContainsPrefix("hello"));
}
[Fact]
public void ContainsPrefix_MatchIsNotSimpleSubstringMatch()
{
// Arrange
var container = new PrefixContainer(new[] { "Hello" });
// Act & Assert
Assert.False(container.ContainsPrefix("He"));
}
[Fact]
public void ContainsPrefix_NonEmptyCollectionReturnsTrueIfPrefixIsEmptyString()
{
// Arrange
var container = new PrefixContainer(new[] { "Hello" });
// Act & Assert
Assert.True(container.ContainsPrefix(""));
}
[Fact]
public void ContainsPrefix_PrefixBoundaries()
{
// Arrange
var container = new PrefixContainer(new[] { "Hello.There[0]" });
// Act & Assert
Assert.True(container.ContainsPrefix("hello"));
Assert.True(container.ContainsPrefix("hello.there"));
Assert.True(container.ContainsPrefix("hello.there[0]"));
Assert.False(container.ContainsPrefix("hello.there.0"));
}
[Theory]
[InlineData("a")]
[InlineData("a[d]")]
[InlineData("c.b")]
[InlineData("c.b.a")]
public void ContainsPrefix_PositiveTests(string testValue)
{
// Arrange
var container = new PrefixContainer(new[] { "a.b", "c.b.a", "a[d]", "a.c" });
// Act & Assert
Assert.True(container.ContainsPrefix(testValue));
}
[Theory]
[InlineData("a.d")]
[InlineData("b")]
[InlineData("c.a")]
[InlineData("c.b.a.a")]
public void ContainsPrefix_NegativeTests(string testValue)
{
// Arrange
var container = new PrefixContainer(new[] { "a.b", "c.b.a", "a[d]", "a.c" });
// Act & Assert
Assert.False(container.ContainsPrefix(testValue));
}
[Fact]
public void ContainsPrefix_ShouldIdentifyCollectionWhenNonCollectionPropertyOccursOnBinarySearchBoundary()
{
// Arrange
var container = new PrefixContainer(new[] { "foo.a", "foo.b", "foo.c", "foo.d", "foo.esSomethingElse", "foo.es[0].a", "foo.es[0].b", "foo.es[0].c", "foo.es[0].d", "foo.es[0].e" });
// Act & Assert
Assert.True(container.ContainsPrefix("foo.es"));
}
[Fact]
public void ContainsPrefix_ShouldIdentifyCollectionWhenNonCollectionPropertyDoesNotOccurOnBinarySearchBoundary()
{
// Arrange
var container = new PrefixContainer(new[] { "foo.a", "foo.b", "foo.c", "foo.d", "foo.esSomethingElse", "foo.es[0].a", "foo.es[0].b", "foo.es[0].c" });
// Act & Assert
Assert.True(container.ContainsPrefix("foo.es"));
}
[Fact]
public void GetKeysFromPrefix_DotsNotation()
{
// Arrange
var container = new PrefixContainer(new[] { "foo.bar.baz", "something.other", "foo.baz", "foot.hello", "fo.nothing", "foo" });
string prefix = "foo";
// Act
IDictionary<string, string> result = container.GetKeysFromPrefix(prefix);
// Assert
Assert.Equal(2, result.Count());
Assert.True(result.ContainsKey("bar"));
Assert.True(result.ContainsKey("baz"));
Assert.Equal("foo.bar", result["bar"]);
Assert.Equal("foo.baz", result["baz"]);
}
[Fact]
public void GetKeysFromPrefix_BracketsNotation()
{
// Arrange
var container = new PrefixContainer(new[] { "foo[bar]baz", "something[other]", "foo[baz]", "foot[hello]", "fo[nothing]", "foo" });
string prefix = "foo";
// Act
IDictionary<string, string> result = container.GetKeysFromPrefix(prefix);
// Assert
Assert.Equal(2, result.Count());
Assert.True(result.ContainsKey("bar"));
Assert.True(result.ContainsKey("baz"));
Assert.Equal("foo[bar]", result["bar"]);
Assert.Equal("foo[baz]", result["baz"]);
}
[Fact]
public void GetKeysFromPrefix_MixedDotsAndBrackets()
{
// Arrange
var container = new PrefixContainer(new[] { "foo[bar]baz", "something[other]", "foo.baz", "foot[hello]", "fo[nothing]", "foo" });
string prefix = "foo";
// Act
IDictionary<string, string> result = container.GetKeysFromPrefix(prefix);
// Assert
Assert.Equal(2, result.Count());
Assert.True(result.ContainsKey("bar"));
Assert.True(result.ContainsKey("baz"));
Assert.Equal("foo[bar]", result["bar"]);
Assert.Equal("foo.baz", result["baz"]);
}
[Fact]
public void GetKeysFromPrefix_AllValues()
{
// Arrange
var container = new PrefixContainer(new[] { "foo[bar]baz", "something[other]", "foo.baz", "foot[hello]", "fo[nothing]", "foo" });
string prefix = "";
// Act
IDictionary<string, string> result = container.GetKeysFromPrefix(prefix);
// Assert
Assert.Equal(4, result.Count());
Assert.Equal("foo", result["foo"]);
Assert.Equal("something", result["something"]);
Assert.Equal("foot", result["foot"]);
Assert.Equal("fo", result["fo"]);
}
[Fact]
public void GetKeysFromPrefix_PrefixNotFound()
{
// Arrange
var container = new PrefixContainer(new[] { "foo[bar]", "something[other]", "foo.baz", "foot[hello]", "fo[nothing]", "foo" });
string prefix = "notfound";
// Act
IDictionary<string, string> result = container.GetKeysFromPrefix(prefix);
// Assert
Assert.Empty(result);
}
}
}

Просмотреть файл

@ -0,0 +1,226 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
#if ASPNETWEBAPI
using System.Web.Http.Routing.Constraints;
#else
using System.Web.Mvc.Routing.Constraints;
#endif
using Microsoft.TestCommon;
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class DefaultInlineConstraintResolverTest
{
[Fact]
public void ResolveConstraint_AlphaConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("alpha");
Assert.IsType<AlphaRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_BoolConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("bool");
Assert.IsType<BoolRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_CompoundConstraintIsNotRegistered()
{
Assert.Null(new DefaultInlineConstraintResolver().ResolveConstraint("compound"));
}
[Fact]
public void ResolveConstraint_DateTimeConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("datetime");
Assert.IsType<DateTimeRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_DecimalConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("decimal");
Assert.IsType<DecimalRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_DoubleConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("double");
Assert.IsType<DoubleRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_EnumNameConstraintIsNotRegistered()
{
Assert.Null(new DefaultInlineConstraintResolver().ResolveConstraint("enumname"));
}
[Fact]
public void ResolveConstraint_EnumValueConstraintIsNotRegistered()
{
Assert.Null(new DefaultInlineConstraintResolver().ResolveConstraint("enumvalue"));
}
[Fact]
public void ResolveConstraint_FloatConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("float");
Assert.IsType<FloatRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_GuidConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("guid");
Assert.IsType<GuidRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_IntConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("int");
Assert.IsType<IntRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_LengthConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("length(5)");
Assert.IsType<LengthRouteConstraint>(constraint);
Assert.Equal(5, ((LengthRouteConstraint)constraint).Length);
}
[Fact]
public void ResolveConstraint_LengthRangeConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("length(5, 10)");
Assert.IsType<LengthRouteConstraint>(constraint);
LengthRouteConstraint lengthConstraint = (LengthRouteConstraint)constraint;
Assert.Equal(5, lengthConstraint.MinLength);
Assert.Equal(10, lengthConstraint.MaxLength);
}
[Fact]
public void ResolveConstraint_LongRangeConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("long");
Assert.IsType<LongRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_MaxConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("max(10)");
Assert.IsType<MaxRouteConstraint>(constraint);
Assert.Equal(10, ((MaxRouteConstraint)constraint).Max);
}
[Fact]
public void ResolveConstraint_MaxLengthConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("maxlength(10)");
Assert.IsType<MaxLengthRouteConstraint>(constraint);
Assert.Equal(10, ((MaxLengthRouteConstraint)constraint).MaxLength);
}
[Fact]
public void ResolveConstraint_MinConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("min(3)");
Assert.IsType<MinRouteConstraint>(constraint);
Assert.Equal(3, ((MinRouteConstraint)constraint).Min);
}
[Fact]
public void ResolveConstraint_MinLengthConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("minlength(3)");
Assert.IsType<MinLengthRouteConstraint>(constraint);
Assert.Equal(3, ((MinLengthRouteConstraint)constraint).MinLength);
}
[Fact]
public void ResolveConstraint_OptionalConstraintIsNotRegistered()
{
Assert.Null(new DefaultInlineConstraintResolver().ResolveConstraint("optional"));
}
[Fact]
public void ResolveConstraint_RangeConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("range(5, 10)");
Assert.IsType<RangeRouteConstraint>(constraint);
RangeRouteConstraint rangeConstraint = (RangeRouteConstraint)constraint;
Assert.Equal(5, rangeConstraint.Min);
Assert.Equal(10, rangeConstraint.Max);
}
[Fact]
public void ResolveConstraint_RegexConstraint()
{
var constraint = new DefaultInlineConstraintResolver().ResolveConstraint("regex(abc,defg)");
Assert.IsType<RegexRouteConstraint>(constraint);
RegexRouteConstraint regexConstraint = (RegexRouteConstraint)constraint;
Assert.Equal("abc,defg", regexConstraint.Pattern);
}
[Fact]
public void ResolveConstraint_IntConstraintWithArgument_Throws()
{
Assert.Throws<InvalidOperationException>(
() => new DefaultInlineConstraintResolver().ResolveConstraint("int(5)"),
"Could not find a constructor for constraint type 'IntRouteConstraint' with the following number of parameters: 1.");
}
[Fact]
public void ResolveConstraint_SupportsCustomConstraints()
{
var resolver = new DefaultInlineConstraintResolver();
resolver.ConstraintMap.Add("custom", typeof(IntRouteConstraint));
var constraint = resolver.ResolveConstraint("custom");
Assert.IsType<IntRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_CustomConstraintThatDoesNotImplementouteConstraintInterfact_Throws()
{
var resolver = new DefaultInlineConstraintResolver();
resolver.ConstraintMap.Add("custom", typeof(string));
Assert.Throws<InvalidOperationException>(
() => resolver.ResolveConstraint("custom"),
#if ASPNETWEBAPI
"The constraint type 'String' which is mapped to constraint key 'custom' must implement the IHttpRouteConstraint interface.");
#else
"The constraint type 'String' which is mapped to constraint key 'custom' must implement the IRouteConstraint interface.");
#endif
}
}
}

Просмотреть файл

@ -0,0 +1,214 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
#if ASPNETWEBAPI
using System.Net.Http;
using System.Web.Http.Routing.Constraints;
#else
using System.Web.Mvc.Routing.Constraints;
#endif
using Microsoft.TestCommon;
using Moq;
#if ASPNETWEBAPI
using TActionDescriptor = System.Web.Http.Controllers.HttpActionDescriptor;
using TParsedRoute = System.Web.Http.Routing.HttpParsedRoute;
using TRouteValueDictionary = System.Web.Http.Routing.HttpRouteValueDictionary;
#else
using TActionDescriptor = System.Web.Mvc.ActionDescriptor;
using TParsedRoute = System.Web.Mvc.Routing.ParsedRoute;
using TRouteValueDictionary = System.Web.Routing.RouteValueDictionary;
#endif
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class DirectRouteBuilderTests
{
[Fact]
public void CreateRoute_ValidatesConstraintType_TRouteConstraint()
{
// Arrange
var actions = GetActions();
var builder = new DirectRouteBuilder(actions, targetIsAction: true);
var constraint = new AlphaRouteConstraint();
var constraints = new TRouteValueDictionary();
constraints.Add("custom", constraint);
builder.Constraints = constraints;
// Act
var routeEntry = builder.Build();
// Assert
Assert.NotNull(routeEntry.Route.Constraints["custom"]);
}
[Fact]
public void BuildRoute_ValidatesConstraintType_StringRegex()
{
// Arrange
var actions = GetActions();
var builder = new DirectRouteBuilder(actions, targetIsAction: true);
var constraint = "product|products";
var constraints = new TRouteValueDictionary();
constraints.Add("custom", constraint);
builder.Constraints = constraints;
// Act
var routeEntry = builder.Build();
// Assert
Assert.NotNull(routeEntry.Route.Constraints["custom"]);
}
[Fact]
public void BuildRoute_ValidatesConstraintType_InvalidType()
{
// Arrange
var actions = GetActions();
var builder = new DirectRouteBuilder(actions, targetIsAction: true);
var constraint = new Uri("http://localhost/");
var constraints = new TRouteValueDictionary();
constraints.Add("custom", constraint);
builder.Constraints = constraints;
builder.Template = "c/{id}";
#if ASPNETWEBAPI
string expectedMessage =
"The constraint entry 'custom' on the route with route template 'c/{id}' " +
"must have a string value or be of a type which implements 'System.Web.Http.Routing.IHttpRouteConstraint'.";
#else
string expectedMessage =
"The constraint entry 'custom' on the route with route template 'c/{id}' " +
"must have a string value or be of a type which implements 'System.Web.Routing.IRouteConstraint'.";
#endif
// Act & Assert
Assert.Throws<InvalidOperationException>(() => builder.Build(), expectedMessage);
}
[Fact]
public void BuildRoute_ValidatesAllowedParameters()
{
// Arrange
var actions = GetActions();
var builder = new MockDirectRouteBuilder(actions, targetIsAction: true);
builder.Template = "{a}/{b}";
// Act
RouteEntry entry = builder.Build();
// Assert
Assert.NotNull(entry);
Assert.Equal(1, builder.TimesValidateParametersCalled);
}
[Theory]
[InlineData("{controller}", true)]
[InlineData("{controller}", false)]
[InlineData("{z}-abc-{controller}", true)]
public void BuildRoute_ControllerParameterNotAllowed(string template, bool targetIsAction)
{
// Arrange
var actions = GetActions();
var expectedMessage =
"A direct route cannot use the parameter 'controller'. " +
"Specify a literal path in place of this parameter to create a route to a controller.";
var builder = new MockDirectRouteBuilder(actions, targetIsAction);
builder.Template = template;
// Act & Assert
Assert.Throws<InvalidOperationException>(() => builder.Build(), expectedMessage);
Assert.Equal(1, builder.TimesValidateParametersCalled);
}
[Fact]
public void BuildRoute_ActionParameterAllowed_OnControllerRoute()
{
// Arrange
var actions = GetActions();
var builder = new MockDirectRouteBuilder(actions, targetIsAction: false);
builder.Template = "{a}/{action}";
// Act
RouteEntry entry = builder.Build();
// Assert
Assert.NotNull(entry);
Assert.Equal(1, builder.TimesValidateParametersCalled);
}
[Theory]
[InlineData("{action}")]
[InlineData("api/yy-{action}")]
public void BuildRoute_ActionNotAllowed_OnActionRoute(string template)
{
// Arrange
var actions = GetActions();
var expectedMessage =
"A direct route for an action method cannot use the parameter 'action'. " +
"Specify a literal path in place of this parameter to create a route to the action.";
var builder = new MockDirectRouteBuilder(actions, targetIsAction: true);
builder.Template = template;
// Act & Assert
Assert.Throws<InvalidOperationException>(() => builder.Build(), expectedMessage);
Assert.Equal(1, builder.TimesValidateParametersCalled);
}
#if ASPNETWEBAPI
private IReadOnlyCollection<TActionDescriptor> GetActions()
{
var actions = new List<TActionDescriptor>()
{
new Mock<TActionDescriptor>().Object,
};
return actions.AsReadOnly();
}
#else
private IReadOnlyCollection<TActionDescriptor> GetActions()
{
var action = new Mock<ActionDescriptor>();
action.SetupGet(a => a.ControllerDescriptor).Returns(new Mock<ControllerDescriptor>().Object);
var actions = new List<ActionDescriptor>()
{
action.Object,
};
return actions.AsReadOnly();
}
#endif
private class MockDirectRouteBuilder : DirectRouteBuilder
{
public MockDirectRouteBuilder(IReadOnlyCollection<TActionDescriptor> actionDescriptors, bool targetIsAction)
: base(actionDescriptors, targetIsAction)
{
}
public int TimesValidateParametersCalled
{
get;
private set;
}
internal override void ValidateParameters(TParsedRoute parsedRoute)
{
TimesValidateParametersCalled++;
base.ValidateParameters(parsedRoute);
}
}
}
}

Просмотреть файл

@ -0,0 +1,254 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Linq;
#if ASPNETWEBAPI
using System.Web.Http.Routing.Constraints;
#else
using System.Web.Mvc.Routing.Constraints;
using System.Web.Routing;
#endif
using Microsoft.TestCommon;
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class InlineRouteTemplateParserTests
{
#if ASPNETWEBAPI
private static readonly RouteParameter OptionalParameter = RouteParameter.Optional;
#else
private static readonly UrlParameter OptionalParameter = UrlParameter.Optional;
#endif
[Fact]
public void ParseRouteTemplate_ChainedConstraintAndDefault()
{
var result = Act(@"hello/{param:int=111111}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal("111111", result.Defaults["param"]);
Assert.IsType<IntRouteConstraint>(result.Constraints["param"]);
}
[Fact]
public void ParseRouteTemplate_ChainedConstraintWithArgumentsAndDefault()
{
var result = Act(@"hello/{param:regex(\d+)=111111}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal("111111", result.Defaults["param"]);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\d+", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_ChainedConstraintAndOptional()
{
var result = Act(@"hello/{param:int?}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal(OptionalParameter, result.Defaults["param"]);
Assert.IsType<OptionalRouteConstraint>(result.Constraints["param"]);
var constraint = (OptionalRouteConstraint)result.Constraints["param"];
Assert.IsType<IntRouteConstraint>(constraint.InnerConstraint);
}
[Fact]
public void ParseRouteTemplate_ChainedConstraintWithArgumentsAndOptional()
{
var result = Act(@"hello/{param:regex(\d+)?}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal(OptionalParameter, result.Defaults["param"]);
Assert.IsType<OptionalRouteConstraint>(result.Constraints["param"]);
var constraint = (OptionalRouteConstraint)result.Constraints["param"];
Assert.Equal(@"\d+", ((RegexRouteConstraint)constraint.InnerConstraint).Pattern);
}
[Fact]
public void ParseRouteTemplate_ChainedConstraints()
{
var result = Act(@"hello/{param:regex(\d+):regex(\w+)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<CompoundRouteConstraint>(result.Constraints["param"]);
CompoundRouteConstraint constraint = (CompoundRouteConstraint)result.Constraints["param"];
Assert.Equal(@"\d+", ((RegexRouteConstraint)constraint.Constraints.ElementAt(0)).Pattern);
Assert.Equal(@"\w+", ((RegexRouteConstraint)constraint.Constraints.ElementAt(1)).Pattern);
}
[Fact]
public void ParseRouteTemplate_Constraint()
{
var result = Act(@"hello/{param:regex(\d+)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\d+", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_ConstraintsDefaultsAndOptionalsInMultipleSections()
{
var result = Act(@"some/url-{p1:alpha:length(3)=hello}/{p2=abc}/{p3?}");
Assert.Equal("some/url-{p1}/{p2}/{p3}", result.RouteUrl);
Assert.Equal("hello", result.Defaults["p1"]);
Assert.Equal("abc", result.Defaults["p2"]);
Assert.Equal(OptionalParameter, result.Defaults["p3"]);
Assert.IsType<CompoundRouteConstraint>(result.Constraints["p1"]);
CompoundRouteConstraint constraint = (CompoundRouteConstraint)result.Constraints["p1"];
Assert.IsType<AlphaRouteConstraint>(constraint.Constraints.ElementAt(0));
Assert.IsType<LengthRouteConstraint>(constraint.Constraints.ElementAt(1));
}
[Fact]
public void ParseRouteTemplate_NoTokens()
{
var result = Act("hello/world");
Assert.Equal("hello/world", result.RouteUrl);
}
[Fact]
public void ParseRouteTemplate_OptionalParam()
{
var result = Act("hello/{param?}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal(OptionalParameter, result.Defaults["param"]);
}
[Fact]
public void ParseRouteTemplate_ParamDefault()
{
var result = Act("hello/{param=world}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.Equal("world", result.Defaults["param"]);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithClosingBraceInPattern()
{
var result = Act(@"hello/{param:regex(\})}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\}", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithClosingParenInPattern()
{
var result = Act(@"hello/{param:regex(\))}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\)", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithColonInPattern()
{
var result = Act(@"hello/{param:regex(:)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@":", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithCommaInPattern()
{
var result = Act(@"hello/{param:regex(\w,\w)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\w,\w", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithEqualsSignInPattern()
{
var result = Act(@"hello/{param:regex(=)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.DoesNotContain("param", result.Defaults.Keys);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"=", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithOpenBraceInPattern()
{
var result = Act(@"hello/{param:regex(\{)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\{", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithOpenParenInPattern()
{
var result = Act(@"hello/{param:regex(\()}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\(", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
[Fact]
public void ParseRouteTemplate_RegexConstraintWithQuestionMarkInPattern()
{
var result = Act(@"hello/{param:regex(\?)}");
Assert.Equal("hello/{param}", result.RouteUrl);
Assert.DoesNotContain("param", result.Defaults.Keys);
Assert.IsType<RegexRouteConstraint>(result.Constraints["param"]);
Assert.Equal(@"\?", ((RegexRouteConstraint)result.Constraints["param"]).Pattern);
}
private ParseResult Act(string template)
{
var result = new ParseResult();
#if ASPNETWEBAPI
result.Constraints = new HttpRouteValueDictionary();
result.Defaults = new HttpRouteValueDictionary();
#else
result.Constraints = new RouteValueDictionary();
result.Defaults = new RouteValueDictionary();
#endif
result.RouteUrl = InlineRouteTemplateParser.ParseRouteTemplate(template, result.Defaults, result.Constraints, new DefaultInlineConstraintResolver());
return result;
}
struct ParseResult
{
public string RouteUrl;
#if ASPNETWEBAPI
public HttpRouteValueDictionary Defaults;
public HttpRouteValueDictionary Constraints;
#else
public RouteValueDictionary Defaults;
public RouteValueDictionary Constraints;
#endif
}
}
}

Просмотреть файл

@ -0,0 +1,362 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq.Expressions;
#if ASPNETWEBAPI
using System.Net.Http;
using System.Web.Http.Routing.Constraints;
#else
using System.Web.Mvc.Routing.Constraints;
using System.Web.Routing;
#endif
using Microsoft.TestCommon;
using Moq;
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class RouteConstraintsTests
{
[Theory]
[InlineData(42, true)]
[InlineData("42", true)]
[InlineData(3.14, false)]
[InlineData("43.567", false)]
[InlineData("42a", false)]
public void IntRouteConstraintTests(object parameterValue, bool expected)
{
var constraint = new IntRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(42, true)]
[InlineData("42", true)]
[InlineData("9223372036854775807", true)]
[InlineData(3.14, false)]
[InlineData("43.567", false)]
[InlineData("42a", false)]
public void LongRouteConstraintTests(object parameterValue, bool expected)
{
Console.WriteLine(long.MaxValue);
var constraint = new LongRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(@"^\d{3}-\d{3}-\d{4}$", "406-555-0123", true)]
[InlineData(@"^\d{3}$", "1234", false)]
public void RegexRouteConstraintTests(string pattern, string parameterValue, bool expected)
{
var constraint = new RegexRouteConstraint(pattern);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("alpha", true)]
[InlineData("a1pha", false)]
[InlineData("", true)]
public void AlphaRouteConstraintTests(string parameterValue, bool expected)
{
var constraint = new AlphaRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(long.MinValue, long.MaxValue, 2, true)]
[InlineData(3, 5, 4, true)]
[InlineData(3, 5, 5, true)]
[InlineData(3, 5, 3, true)]
[InlineData(3, 5, 6, false)]
[InlineData(3, 5, 2, false)]
[InlineData(3, 1, 2, false)]
public void RangeRouteConstraintTests(long min, long max, int parameterValue, bool expected)
{
var constraint = new RangeRouteConstraint(min, max);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, 4, true)]
[InlineData(3, 3, true)]
[InlineData(3, 2, false)]
public void MinRouteConstraintTests(long min, int parameterValue, bool expected)
{
var constraint = new MinRouteConstraint(min);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, 2, true)]
[InlineData(3, 3, true)]
[InlineData(3, 4, false)]
public void MaxRouteConstraintTests(long max, int parameterValue, bool expected)
{
var constraint = new MaxRouteConstraint(max);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, "1234", true)]
[InlineData(3, "123", true)]
[InlineData(3, "12", false)]
[InlineData(3, "", false)]
public void MinLengthRouteConstraintTests(int min, string parameterValue, bool expected)
{
var constraint = new MinLengthRouteConstraint(min);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, "", true)]
[InlineData(3, "12", true)]
[InlineData(3, "123", true)]
[InlineData(3, "1234", false)]
public void MaxLengthRouteConstraintTests(int min, string parameterValue, bool expected)
{
var constraint = new MaxLengthRouteConstraint(min);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, "123", true)]
[InlineData(3, "1234", false)]
public void LengthRouteConstraint_ExactLength_Tests(int length, string parameterValue, bool expected)
{
var constraint = new LengthRouteConstraint(length);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, 5, "12", false)]
[InlineData(3, 5, "123", true)]
[InlineData(3, 5, "1234", true)]
[InlineData(3, 5, "12345", true)]
[InlineData(3, 5, "123456", false)]
public void LengthRouteConstraint_Range_Tests(int min, int max, string parameterValue, bool expected)
{
var constraint = new LengthRouteConstraint(min, max);
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("12345678-1234-1234-1234-123456789012", false, true)]
[InlineData("12345678-1234-1234-1234-123456789012", true, true)]
[InlineData("12345678901234567890123456789012", false, true)]
[InlineData("not-parseable-as-guid", false, false)]
[InlineData(12, false, false)]
public void GuidRouteConstraintTests(object parameterValue, bool parseBeforeTest, bool expected)
{
if (parseBeforeTest)
{
parameterValue = Guid.Parse(parameterValue.ToString());
}
var constraint = new GuidRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("3.14", true)]
[InlineData(3.14f, true)]
[InlineData("not-parseable-as-float", false)]
[InlineData(false, false)]
[InlineData("1.79769313486232E+300", false)]
public void FloatRouteConstraintTests(object parameterValue, bool expected)
{
var constraint = new FloatRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("3.14", true)]
[InlineData(3.14f, true)]
[InlineData("1.79769313486232E+300", true)]
[InlineData("not-parseable-as-double", false)]
[InlineData(false, false)]
public void DoubleRouteConstraintTests(object parameterValue, bool expected)
{
var constraint = new DoubleRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("3.14", true)]
[InlineData("9223372036854775808.9223372036854775808", true)]
[InlineData("1.79769313486232E+300", false)]
[InlineData("not-parseable-as-decimal", false)]
[InlineData(false, false)]
public void DecimalRouteConstraintTests(object parameterValue, bool expected)
{
var constraint = new DecimalRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("12/25/2009", true)]
[InlineData("12/25/2009 11:45:00 PM", true)]
[InlineData("11:45:00 PM", true)]
[InlineData("2009-05-12T11:45:00Z", true)]
[InlineData("not-parseable-as-date", false)]
[InlineData(false, false)]
public void DateTimeRouteConstraint(object parameterValue, bool expected)
{
var constraint = new DateTimeRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("true", true)]
[InlineData("false", true)]
[InlineData(true, true)]
[InlineData(false, true)]
[InlineData(1, false)]
[InlineData("not-parseable-as-bool", false)]
public void BoolRouteConstraint(object parameterValue, bool expected)
{
var constraint = new BoolRouteConstraint();
var actual = TestValue(constraint, parameterValue);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(null, false, true)]
[InlineData("pass", true, true)]
[InlineData("fail", true, false)]
public void OptionalRouteConstraintTests(object parameterValue, bool shouldCallInner, bool expected)
{
// Arrange
var inner = MockConstraintWithResult((string)parameterValue != "fail");
// Act
var constraint = new OptionalRouteConstraint(inner.Object);
#if ASPNETWEBAPI
var optionalParameter = RouteParameter.Optional;
#else
var optionalParameter = UrlParameter.Optional;
#endif
var actual = TestValue(constraint, parameterValue ?? optionalParameter, route =>
{
route.Defaults.Add("fake", optionalParameter);
});
// Assert
Assert.Equal(expected, actual);
var timeMatchShouldHaveBeenCalled = shouldCallInner
? Times.Once()
: Times.Never();
AssertMatchWasCalled(inner, timeMatchShouldHaveBeenCalled);
}
[Theory]
[InlineData(true, true, true)]
[InlineData(true, false, false)]
[InlineData(false, true, false)]
[InlineData(false, false, false)]
public void CompoundRouteConstraintTests(bool inner1Result, bool inner2Result, bool expected)
{
// Arrange
var inner1 = MockConstraintWithResult(inner1Result);
var inner2 = MockConstraintWithResult(inner2Result);
// Act
var constraint = new CompoundRouteConstraint(new[] { inner1.Object, inner2.Object });
var actual = TestValue(constraint, null);
// Assert
Assert.Equal(expected, actual);
}
#if ASPNETWEBAPI
static Expression<Func<IHttpRouteConstraint, bool>> ConstraintMatchMethodExpression =
c => c.Match(It.IsAny<HttpRequestMessage>(), It.IsAny<IHttpRoute>(), It.IsAny<string>(), It.IsAny<IDictionary<string, object>>(), It.IsAny<HttpRouteDirection>());
private static Mock<IHttpRouteConstraint> MockConstraintWithResult(bool result)
{
var mock = new Mock<IHttpRouteConstraint>();
mock.Setup(ConstraintMatchMethodExpression)
.Returns(result)
.Verifiable();
return mock;
}
private static void AssertMatchWasCalled(Mock<IHttpRouteConstraint> mock, Times times)
{
mock.Verify(ConstraintMatchMethodExpression, times);
}
private static bool TestValue(IHttpRouteConstraint constraint, object value, Action<IHttpRoute> routeConfig = null)
{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage();
HttpRoute httpRoute = new HttpRoute();
if (routeConfig != null)
{
routeConfig(httpRoute);
}
const string parameterName = "fake";
HttpRouteValueDictionary values = new HttpRouteValueDictionary { { parameterName, value } };
const HttpRouteDirection httpRouteDirection = HttpRouteDirection.UriResolution;
return constraint.Match(httpRequestMessage, httpRoute, parameterName, values, httpRouteDirection);
}
#else
static Expression<Func<IRouteConstraint, bool>> ConstraintMatchMethodExpression =
c => c.Match(It.IsAny<HttpContextBase>(), It.IsAny<Route>(), It.IsAny<string>(), It.IsAny<RouteValueDictionary>(), It.IsAny<RouteDirection>());
private static Mock<IRouteConstraint> MockConstraintWithResult(bool result)
{
var mock = new Mock<IRouteConstraint>();
mock.Setup(ConstraintMatchMethodExpression)
.Returns(result)
.Verifiable();
return mock;
}
private static void AssertMatchWasCalled(Mock<IRouteConstraint> mock, Times times)
{
mock.Verify(ConstraintMatchMethodExpression, times);
}
private static bool TestValue(IRouteConstraint constraint, object value, Action<Route> routeConfig = null)
{
var context = new Mock<HttpContextBase>();
Route route = new Route("", null);
route.Defaults = new RouteValueDictionary();
if (routeConfig != null)
{
routeConfig(route);
}
const string parameterName = "fake";
RouteValueDictionary values = new RouteValueDictionary { { parameterName, value } };
const RouteDirection routeDirection = RouteDirection.IncomingRequest;
return constraint.Match(context.Object, route, parameterName, values, routeDirection);
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,598 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.Contracts;
#if ASPNETWEBAPI
using System.Web.Http.Controllers;
#endif
using Microsoft.TestCommon;
using Moq;
#if ASPNETWEBAPI
using TActionDescriptor = System.Web.Http.Controllers.HttpActionDescriptor;
using TRoute = System.Web.Http.Routing.IHttpRoute;
using TRouteDictionary = System.Collections.Generic.IDictionary<string, object>;
using TRouteDictionaryConcrete = System.Web.Http.Routing.HttpRouteValueDictionary;
#else
using TActionDescriptor = System.Web.Mvc.ActionDescriptor;
using TRoute = System.Web.Routing.Route;
using TRouteDictionary = System.Web.Routing.RouteValueDictionary;
using TRouteDictionaryConcrete = System.Web.Routing.RouteValueDictionary;
#endif
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class RouteFactoryAttributeTests
{
[Fact]
public void TemplateGet_ReturnsSpecifiedInstance()
{
// Arrange
string expectedTemplate = "RouteTemplate";
RouteFactoryAttribute product = CreateProductUnderTest(expectedTemplate);
// Act
string template = product.Template;
// Assert
Assert.Same(expectedTemplate, template);
}
[Fact]
public void NameGet_ReturnsNull()
{
// Arrange
RouteFactoryAttribute product = CreateProductUnderTest();
// Act
string name = product.Name;
// Assert
Assert.Null(name);
}
[Fact]
public void OrderGet_ReturnsZero()
{
// Arrange
RouteFactoryAttribute product = CreateProductUnderTest();
// Act
int order = product.Order;
// Assert
Assert.Equal(0, order);
}
[Fact]
public void ConstraintsGet_ReturnsNull()
{
// Arrange
RouteFactoryAttribute product = CreateProductUnderTest();
// Act
TRouteDictionary constraints = product.Constraints;
// Assert
Assert.Null(constraints);
}
[Fact]
public void CreateRoute_DelegatesToContextCreateBuilderBuild()
{
// Arrange
string expectedTemplate = "RouteTemplate";
IDirectRouteFactory product = CreateProductUnderTest(expectedTemplate);
RouteEntry expectedEntry = CreateEntry();
IDirectRouteBuilder builder = CreateBuilder(() => expectedEntry);
DirectRouteFactoryContext context = CreateContext((template) => template == expectedTemplate ? builder :
new DirectRouteBuilder(new TActionDescriptor[0], targetIsAction: true));
// Act
RouteEntry entry = product.CreateRoute(context);
// Assert
Assert.Same(expectedEntry, entry);
}
[Fact]
public void CreateRoute_IfContextIsNull_Throws()
{
// Arrange
DirectRouteFactoryContext context = null;
IDirectRouteFactory product = CreateProductUnderTest();
// Act & Assert
Assert.ThrowsArgumentNull(() => product.CreateRoute(context), "context");
}
[Fact]
public void CreateRoute_UsesNamePropertyWhenBuilding()
{
// Arrange
string expectedName = "RouteName";
RouteFactoryAttribute product = CreateProductUnderTest();
product.Name = expectedName;
string name = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
name = builder.Name;
return null;
});
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(expectedName, name);
}
[Fact]
public void CreateRoute_UsesOrderPropertyWhenBuilding()
{
// Arrange
int expectedOrder = 123;
RouteFactoryAttribute product = CreateProductUnderTest();
product.Order = expectedOrder;
int order = 0;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
order = builder.Order;
return null;
});
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Equal(expectedOrder, order);
}
[Fact]
public void CreateRoute_IfBuilderDefaultsIsNull_UsesDefaultsPropertyWhenBuilding()
{
// Arrange
TRouteDictionary expectedDefaults = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Defaults).Returns(expectedDefaults);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary defaults = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
defaults = builder.Defaults;
return null;
});
Assert.Null(builder.Defaults); // Guard
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(expectedDefaults, defaults);
}
[Fact]
public void CreateRoute_IfBuilderDefaultsIsNotNull_UpdatesDefaultsFromPropertyWhenBuilding()
{
// Arrange
TRouteDictionary existingDefaults = new TRouteDictionaryConcrete();
string existingDefaultKey = "ExistingDefaultKey";
object existingDefaultValue = "ExistingDefault";
existingDefaults.Add(existingDefaultKey, existingDefaultValue);
string conflictingDefaultKey = "ConflictingDefaultKey";
object oldConflictingDefaultValue = "OldConflictingDefault";
existingDefaults.Add(conflictingDefaultKey, oldConflictingDefaultValue);
TRouteDictionary additionalDefaults = new TRouteDictionaryConcrete();
string additionalDefaultKey = "NewDefaultKey";
string additionalDefaultValue = "NewDefault";
additionalDefaults.Add(additionalDefaultKey, additionalDefaultValue);
string newConflictingDefaultValue = "NewConflictingDefault";
additionalDefaults.Add(conflictingDefaultKey, newConflictingDefaultValue);
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Defaults).Returns(additionalDefaults);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary defaults = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
defaults = builder.Defaults;
return null;
});
builder.Defaults = existingDefaults;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingDefaults, defaults);
Assert.Equal(3, defaults.Count);
Assert.True(defaults.ContainsKey(existingDefaultKey));
Assert.Same(existingDefaultValue, defaults[existingDefaultKey]);
Assert.True(defaults.ContainsKey(conflictingDefaultKey));
Assert.Same(newConflictingDefaultValue, defaults[conflictingDefaultKey]);
Assert.True(defaults.ContainsKey(additionalDefaultKey));
Assert.Same(additionalDefaultValue, defaults[additionalDefaultKey]);
}
[Fact]
public void CreateRoute_IfBuilderConstraintsIsNotNullAndDefaultsPropertyIsNull_UsesBuilderDefaults()
{
// Arrange
TRouteDictionary existingDefaults = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Defaults).Returns((TRouteDictionary)null);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary defaults = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
defaults = builder.Defaults;
return null;
});
builder.Defaults = existingDefaults;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingDefaults, defaults);
}
[Fact]
public void CreateRoute_IfBuilderConstraintsIsNull_UsesConstraintsPropertyWhenBuilding()
{
// Arrange
TRouteDictionary expectedConstraints = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Constraints).Returns(expectedConstraints);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary constraints = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
constraints = builder.Constraints;
return null;
});
Assert.Null(builder.Constraints); // Guard
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(expectedConstraints, constraints);
}
[Fact]
public void CreateRoute_IfBuilderConstraintsIsNotNull_UpdatesConstraintsFromPropertyWhenBuilding()
{
// Arrange
TRouteDictionary existingConstraints = new TRouteDictionaryConcrete();
string existingConstraintKey = "ExistingConstraintKey";
object existingConstraintValue = "ExistingConstraint";
existingConstraints.Add(existingConstraintKey, existingConstraintValue);
string conflictingConstraintKey = "ConflictingConstraintKey";
object oldConflictingConstraintValue = "OldConflictingConstraint";
existingConstraints.Add(conflictingConstraintKey, oldConflictingConstraintValue);
TRouteDictionary additionalConstraints = new TRouteDictionaryConcrete();
string additionalConstraintKey = "NewConstraintKey";
string additionalConstraintValue = "NewConstraint";
additionalConstraints.Add(additionalConstraintKey, additionalConstraintValue);
string newConflictingConstraintValue = "NewConflictingConstraint";
additionalConstraints.Add(conflictingConstraintKey, newConflictingConstraintValue);
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Constraints).Returns(additionalConstraints);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary constraints = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
constraints = builder.Constraints;
return null;
});
builder.Constraints = existingConstraints;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingConstraints, constraints);
Assert.Equal(3, constraints.Count);
Assert.True(constraints.ContainsKey(existingConstraintKey));
Assert.Same(existingConstraintValue, constraints[existingConstraintKey]);
Assert.True(constraints.ContainsKey(conflictingConstraintKey));
Assert.Same(newConflictingConstraintValue, constraints[conflictingConstraintKey]);
Assert.True(constraints.ContainsKey(additionalConstraintKey));
Assert.Same(additionalConstraintValue, constraints[additionalConstraintKey]);
}
[Fact]
public void CreateRoute_IfBuilderConstraintsIsNotNullAndConstraintsPropertyIsNull_UsesBuilderConstraints()
{
// Arrange
TRouteDictionary existingConstraints = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.Constraints).Returns((TRouteDictionary)null);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary constraints = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
constraints = builder.Constraints;
return null;
});
builder.Constraints = existingConstraints;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingConstraints, constraints);
}
[Fact]
public void CreateRoute_IfBuilderDataTokensIsNull_UsesDataTokensPropertyWhenBuilding()
{
// Arrange
TRouteDictionary expectedDataTokens = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.DataTokens).Returns(expectedDataTokens);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary dataTokens = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
dataTokens = builder.DataTokens;
return null;
});
Assert.Null(builder.DataTokens); // Guard
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(expectedDataTokens, dataTokens);
}
[Fact]
public void CreateRoute_IfBuilderDataTokensIsNotNull_UpdatesDataTokensFromPropertyWhenBuilding()
{
// Arrange
TRouteDictionary existingDataTokens = new TRouteDictionaryConcrete();
string existingDataTokenKey = "ExistingDataTokenKey";
object existingDataTokenValue = "ExistingDataToken";
existingDataTokens.Add(existingDataTokenKey, existingDataTokenValue);
string conflictingDataTokenKey = "ConflictingDataTokenKey";
object oldConflictingDataTokenValue = "OldConflictingDataToken";
existingDataTokens.Add(conflictingDataTokenKey, oldConflictingDataTokenValue);
TRouteDictionary additionalDataTokens = new TRouteDictionaryConcrete();
string additionalDataTokenKey = "NewDataTokenKey";
string additionalDataTokenValue = "NewDataToken";
additionalDataTokens.Add(additionalDataTokenKey, additionalDataTokenValue);
string newConflictingDataTokenValue = "NewConflictingDataToken";
additionalDataTokens.Add(conflictingDataTokenKey, newConflictingDataTokenValue);
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.DataTokens).Returns(additionalDataTokens);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary dataTokens = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
dataTokens = builder.DataTokens;
return null;
});
builder.DataTokens = existingDataTokens;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingDataTokens, dataTokens);
Assert.Equal(3, dataTokens.Count);
Assert.True(dataTokens.ContainsKey(existingDataTokenKey));
Assert.Same(existingDataTokenValue, dataTokens[existingDataTokenKey]);
Assert.True(dataTokens.ContainsKey(conflictingDataTokenKey));
Assert.Same(newConflictingDataTokenValue, dataTokens[conflictingDataTokenKey]);
Assert.True(dataTokens.ContainsKey(additionalDataTokenKey));
Assert.Same(additionalDataTokenValue, dataTokens[additionalDataTokenKey]);
}
[Fact]
public void CreateRoute_IfBuilderDataTokensIsNotNullAndDataTokensPropertyIsNull_UsesBuilderDataTokens()
{
// Arrange
TRouteDictionary existingDataTokens = new TRouteDictionaryConcrete();
Mock<RouteFactoryAttribute> productMock = CreateProductUnderTestMock();
productMock.SetupGet(p => p.DataTokens).Returns((TRouteDictionary)null);
IDirectRouteFactory product = productMock.Object;
RouteEntry expectedEntry = CreateEntry();
TRouteDictionary dataTokens = null;
IDirectRouteBuilder builder = null;
builder = CreateBuilder(() =>
{
dataTokens = builder.DataTokens;
return null;
});
builder.DataTokens = existingDataTokens;
DirectRouteFactoryContext context = CreateContext((i) => builder);
// Act
RouteEntry ignore = product.CreateRoute(context);
// Assert
Assert.Same(existingDataTokens, dataTokens);
}
[Fact]
public void AttributeUsage_IsAsSpecified()
{
// Act
AttributeUsageAttribute usage = (AttributeUsageAttribute)Attribute.GetCustomAttribute(
typeof(RouteFactoryAttribute), typeof(AttributeUsageAttribute));
// Assert
Assert.NotNull(usage);
Assert.Equal(AttributeTargets.Class | AttributeTargets.Method, usage.ValidOn);
Assert.Equal(false, usage.Inherited);
Assert.Equal(true, usage.AllowMultiple);
}
private static IDirectRouteBuilder CreateBuilder(Func<RouteEntry> build)
{
return new LambdaDirectRouteBuilder(build);
}
private static DirectRouteFactoryContext CreateContext(Func<string, IDirectRouteBuilder> createBuilder)
{
return new LambdaDirectRouteFactoryContext(createBuilder);
}
private static RouteEntry CreateEntry()
{
#if ASPNETWEBAPI
TRoute route = new Mock<TRoute>(MockBehavior.Strict).Object;
#else
TRoute route = new Mock<TRoute>(MockBehavior.Strict, null, null).Object;
#endif
return new RouteEntry("IgnoreEntry", route);
}
private static RouteFactoryAttribute CreateProductUnderTest()
{
return CreateProductUnderTest("IgnoreTemplate");
}
private static RouteFactoryAttribute CreateProductUnderTest(string template)
{
return CreateProductUnderTestMock(template).Object;
}
private static Mock<RouteFactoryAttribute> CreateProductUnderTestMock()
{
return CreateProductUnderTestMock("IgnoreTemplate");
}
private static Mock<RouteFactoryAttribute> CreateProductUnderTestMock(string template)
{
Mock<RouteFactoryAttribute> mock = new Mock<RouteFactoryAttribute>(template);
mock.CallBase = true;
return mock;
}
private class LambdaDirectRouteFactoryContext : DirectRouteFactoryContext
{
private readonly Func<string, IDirectRouteBuilder> _createBuilder;
public LambdaDirectRouteFactoryContext(Func<string, IDirectRouteBuilder> createBuilder)
#if ASPNETWEBAPI
: base(null, new TActionDescriptor[] { new Mock<TActionDescriptor>().Object },
new Mock<IInlineConstraintResolver>(MockBehavior.Strict).Object,
targetIsAction: true)
#else
: base(null, null, new TActionDescriptor[] { CreateStubActionDescriptor() },
new Mock<IInlineConstraintResolver>(MockBehavior.Strict).Object, targetIsAction: true)
#endif
{
Contract.Assert(createBuilder != null);
_createBuilder = createBuilder;
}
internal override IDirectRouteBuilder CreateBuilderInternal(string template)
{
return _createBuilder.Invoke(template);
}
#if !ASPNETWEBAPI
private static ActionDescriptor CreateStubActionDescriptor()
{
Mock<ActionDescriptor> mock = new Mock<TActionDescriptor>();
mock.Setup(m => m.ControllerDescriptor).Returns(new Mock<ControllerDescriptor>().Object);
return mock.Object;
}
#endif
}
private class LambdaDirectRouteBuilder : DirectRouteBuilder
{
private readonly Func<RouteEntry> _build;
public LambdaDirectRouteBuilder(Func<RouteEntry> build)
: base(new TActionDescriptor[0], targetIsAction: true)
{
Contract.Assert(build != null);
_build = build;
}
public override RouteEntry Build()
{
return _build.Invoke();
}
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if !ASPNETWEBAPI
using System.Web.Routing;
#endif
using Microsoft.TestCommon;
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class RoutePrecedenceTests
{
[Theory]
[InlineData("Employees/{id}", "Employees/{id}")]
[InlineData("abc", "def")]
[InlineData("{x:alpha}", "{x:int}")]
public void Compute_IsEqual(string xTemplate, string yTemplate)
{
// Arrange & Act
var xPrededence = Compute(xTemplate);
var yPrededence = Compute(yTemplate);
// Assert
Assert.Equal(xPrededence, yPrededence);
}
[Theory]
[InlineData("abc", "a{x}")]
[InlineData("abc", "{x}c")]
[InlineData("abc", "{x:int}")]
[InlineData("abc", "{x}")]
[InlineData("abc", "{*x}")]
[InlineData("{x:int}", "{x}")]
[InlineData("{x:int}", "{*x}")]
[InlineData("a{x}", "{x}")]
[InlineData("{x}c", "{x}")]
[InlineData("a{x}", "{*x}")]
[InlineData("{x}c", "{*x}")]
[InlineData("{x}", "{*x}")]
[InlineData("{*x:maxlength(10)}", "{*x}")]
[InlineData("abc/def", "abc/{x:int}")]
[InlineData("abc/def", "abc/{x}")]
[InlineData("abc/def", "abc/{*x}")]
[InlineData("abc/{x:int}", "abc/{x}")]
[InlineData("abc/{x:int}", "abc/{*x}")]
[InlineData("abc/{x}", "abc/{*x}")]
[InlineData("{x}/{y:int}", "{x}/{y}")]
public void Compute_IsLessThan(string xTemplate, string yTemplate)
{
// Arrange & Act
var xPrededence = Compute(xTemplate);
var yPrededence = Compute(yTemplate);
// Assert
Assert.True(xPrededence < yPrededence);
}
private static decimal Compute(string template)
{
DefaultInlineConstraintResolver resolver = new DefaultInlineConstraintResolver();
#if ASPNETWEBAPI
HttpRouteValueDictionary defaults = new HttpRouteValueDictionary();
HttpRouteValueDictionary constraints = new HttpRouteValueDictionary();
#else
RouteValueDictionary defaults = new RouteValueDictionary();
RouteValueDictionary constraints = new RouteValueDictionary();
#endif
string standardRouteTemplate = InlineRouteTemplateParser.ParseRouteTemplate(template,
defaults, constraints, new DefaultInlineConstraintResolver());
var parsedRoute = RouteParser.Parse(standardRouteTemplate);
return RoutePrecedence.Compute(parsedRoute, constraints);
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if !ASPNETWEBAPI
using System.Web.Routing;
#endif
using Microsoft.TestCommon;
using Moq;
#if ASPNETWEBAPI
namespace System.Web.Http.Routing
#else
namespace System.Web.Mvc.Routing
#endif
{
public class SubRouteCollectionTest
{
#if ASPNETWEBAPI
[Fact]
public void SubRouteCollection_Throws_OnDuplicateNamedRoute_WebAPI()
{
// Arrange
var collection = new SubRouteCollection();
var route1 = new HttpRoute("api/Person");
var route2 = new HttpRoute("api/Car");
collection.Add(new RouteEntry("route", route1));
var expectedError =
"A route named 'route' is already in the route collection. Route names must be unique.\r\n\r\n" +
"Duplicates:" + Environment.NewLine +
"api/Car" + Environment.NewLine +
"api/Person";
// Act & Assert
Assert.Throws<InvalidOperationException>(() => collection.Add(new RouteEntry("route", route2)), expectedError);
}
#else
[Fact]
public void SubRouteCollection_Throws_OnDuplicateNamedRoute_MVC()
{
// Arrange
var collection = new SubRouteCollection();
var route1 = new Route("Home/Index", new Mock<IRouteHandler>().Object);
var route2 = new Route("Person/Index", new Mock<IRouteHandler>().Object);
collection.Add(new RouteEntry("route", route1));
var expectedError =
"A route named 'route' is already in the route collection. Route names must be unique.\r\n\r\n" +
"Duplicates:" + Environment.NewLine +
"Person/Index" + Environment.NewLine +
"Home/Index";
// Act & Assert
Assert.Throws<InvalidOperationException>(() => collection.Add(new RouteEntry("route", route2)), expectedError);
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,197 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.TestCommon;
using Moq;
namespace System.Threading.Tasks
{
public class TaskHelpersExtensionsTest
{
// ----------------------------------------------------------------
// Task<object> Task<T>.CastToObject()
[Fact, ForceGC]
public Task ConvertFromTaskOfStringShouldSucceed()
{
// Arrange
return Task.FromResult("StringResult")
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
Assert.Equal("StringResult", (string)task.Result);
});
}
[Fact, ForceGC]
public Task ConvertFromTaskOfIntShouldSucceed()
{
// Arrange
return Task.FromResult(123)
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
Assert.Equal(123, (int)task.Result);
});
}
[Fact, ForceGC]
public Task ConvertFromFaultedTaskOfObjectShouldBeHandled()
{
// Arrange
return TaskHelpers.FromError<object>(new InvalidOperationException())
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.Faulted, task.Status);
Assert.IsType<InvalidOperationException>(task.Exception.GetBaseException());
});
}
[Fact, ForceGC]
public Task ConvertFromCancelledTaskOfStringShouldBeHandled()
{
// Arrange
return TaskHelpers.Canceled<string>()
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.Canceled, task.Status);
});
}
// ----------------------------------------------------------------
// Task<object> Task.CastToObject()
[Fact, ForceGC]
public Task ConvertFromTaskShouldSucceed()
{
// Arrange
return TaskHelpers.Completed()
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
Assert.Equal(null, task.Result);
});
}
[Fact, ForceGC]
public Task ConvertFromFaultedTaskShouldBeHandled()
{
// Arrange
return TaskHelpers.FromError(new InvalidOperationException())
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.Faulted, task.Status);
Assert.IsType<InvalidOperationException>(task.Exception.GetBaseException());
});
}
[Fact, ForceGC]
public Task ConvertFromCancelledTaskShouldBeHandled()
{
// Arrange
return TaskHelpers.Canceled()
// Act
.CastToObject()
// Assert
.ContinueWith((task) =>
{
Assert.Equal(TaskStatus.Canceled, task.Status);
});
}
// -----------------------------------------------------------------
// bool Task.TryGetResult(Task<TResult>, out TResult)
[Fact, ForceGC]
public void TryGetResult_CompleteTask_ReturnsTrueAndGivesResult()
{
// Arrange
var task = Task.FromResult(42);
// Act
int value;
bool result = task.TryGetResult(out value);
// Assert
Assert.True(result);
Assert.Equal(42, value);
}
[Fact, ForceGC]
public void TryGetResult_FaultedTask_ReturnsFalse()
{
// Arrange
var task = TaskHelpers.FromError<int>(new Exception());
// Act
int value;
bool result = task.TryGetResult(out value);
// Assert
Assert.False(result);
var ex = task.Exception; // Observe the task exception
}
[Fact, ForceGC]
public void TryGetResult_CanceledTask_ReturnsFalse()
{
// Arrange
var task = TaskHelpers.Canceled<int>();
// Act
int value;
bool result = task.TryGetResult(out value);
// Assert
Assert.False(result);
}
[Fact, ForceGC]
public Task TryGetResult_IncompleteTask_ReturnsFalse()
{
// Arrange
var incompleteTask = new Task<int>(() => 42);
// Act
int value;
bool result = incompleteTask.TryGetResult(out value);
// Assert
Assert.False(result);
incompleteTask.Start();
return incompleteTask; // Make sure the task gets observed
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.TestCommon;
namespace System.Threading.Tasks
{
public class TaskHelpersTest
{
// -----------------------------------------------------------------
// TaskHelpers.Canceled
[Fact]
public void Canceled_ReturnsCanceledTask()
{
Task result = TaskHelpers.Canceled();
Assert.NotNull(result);
Assert.True(result.IsCanceled);
}
// -----------------------------------------------------------------
// TaskHelpers.Canceled<T>
[Fact]
public void Canceled_Generic_ReturnsCanceledTask()
{
Task<string> result = TaskHelpers.Canceled<string>();
Assert.NotNull(result);
Assert.True(result.IsCanceled);
}
// -----------------------------------------------------------------
// TaskHelpers.Completed
[Fact]
public void Completed_ReturnsCompletedTask()
{
Task result = TaskHelpers.Completed();
Assert.NotNull(result);
Assert.Equal(TaskStatus.RanToCompletion, result.Status);
}
// -----------------------------------------------------------------
// TaskHelpers.FromError
[Fact]
public void FromError_ReturnsFaultedTaskWithGivenException()
{
var exception = new Exception();
Task result = TaskHelpers.FromError(exception);
Assert.NotNull(result);
Assert.True(result.IsFaulted);
Assert.Same(exception, result.Exception.InnerException);
}
// -----------------------------------------------------------------
// TaskHelpers.FromError<T>
[Fact]
public void FromError_Generic_ReturnsFaultedTaskWithGivenException()
{
var exception = new Exception();
Task<string> result = TaskHelpers.FromError<string>(exception);
Assert.NotNull(result);
Assert.True(result.IsFaulted);
Assert.Same(exception, result.Exception.InnerException);
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections;
using Microsoft.TestCommon;
namespace System
{
public class TypeExtensionsTest
{
[Theory]
[InlineData(typeof(int), false)]
[InlineData(typeof(string), true)]
[InlineData(typeof(DateTime), false)]
[InlineData(typeof(int?), true)]
[InlineData(typeof(IEnumerable), true)]
[InlineData(typeof(int[]), true)]
[InlineData(typeof(string[]), true)]
public void IsNullable_Returns_ExpectedValue(Type type, bool expectedResult)
{
Assert.Equal(expectedResult, type.IsNullable());
}
}
}

Просмотреть файл

@ -0,0 +1,124 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net.Http.Formatting;
using System.Text;
using System.Web.Http;
using Microsoft.TestCommon;
namespace System.Net.Http
{
public class UriQueryUtilityTest
{
public static TheoryDataSet<string, string, string> UriQueryData
{
get
{
return UriQueryTestData.UriQueryData;
}
}
[Fact]
public void TypeIsCorrect()
{
Assert.Type.HasProperties(typeof(UriQueryUtility), TypeAssert.TypeProperties.IsClass | TypeAssert.TypeProperties.IsStatic);
}
[Fact]
public void UrlEncode_ReturnsNull()
{
Assert.Null(UriQueryUtility.UrlEncode(null));
}
[Fact]
public void UrlDecode_ReturnsNull()
{
Assert.Null(UriQueryUtility.UrlDecode(null));
}
[Fact]
public void UrlDecode_ParsesEmptySegmentsCorrectly()
{
int iterations = 16;
List<string> segments = new List<string>();
for (int index = 1; index < iterations; index++)
{
segments.Add("&");
string query = string.Join("", segments);
NameValueCollection result = ParseQueryString(query);
Assert.NotNull(result);
// Because this is a NameValueCollection, the same name appears only once
Assert.Equal(1, result.Count);
// Values should be a comma separated list of empty strings
string[] values = result[""].Split(new char[] { ',' });
// We expect length+1 segment as the final '&' counts as a segment
Assert.Equal(index + 1, values.Length);
foreach (var value in values)
{
Assert.Equal("", value);
}
}
}
[Theory]
[InlineData("N", "N", "")]
[InlineData("%26", "&", "")]
[InlineData("foo=%u0026", "foo", "%u0026")]
[PropertyData("UriQueryData")]
public void UrlDecode_ParsesCorrectly(string segment, string resultName, string resultValue)
{
int iterations = 16;
List<string> segments = new List<string>();
for (int index = 1; index < iterations; index++)
{
segments.Add(segment);
string query = CreateQuery(segments.ToArray());
NameValueCollection result = ParseQueryString(query);
Assert.NotNull(result);
// Because this is a NameValueCollection, the same name appears only once
Assert.Equal(1, result.Count);
// Values should be a comma separated list of resultValue
string[] values = result[resultName].Split(new char[] { ',' });
Assert.Equal(index, values.Length);
foreach (var value in values)
{
Assert.Equal(resultValue, value);
}
}
}
private static string CreateQuery(params string[] segments)
{
StringBuilder buffer = new StringBuilder();
bool first = true;
foreach (string segment in segments)
{
if (first)
{
first = false;
}
else
{
buffer.Append('&');
}
buffer.Append(segment);
}
return buffer.ToString();
}
private static NameValueCollection ParseQueryString(string query)
{
return new FormDataCollection(query).ReadAsNameValueCollection();
}
}
}

Просмотреть файл

@ -0,0 +1,73 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.IO;
using System.Reflection;
using System.Web.Compilation;
using System.Web.Hosting;
namespace System.Web.WebPages.TestUtils
{
public static class AppDomainUtils
{
// Allow a test to modify static fields in an independent appdomain so that
// other tests will not be affected.
public static void RunInSeparateAppDomain(Action action)
{
RunInSeparateAppDomain(new AppDomainSetup(), action);
}
public static void RunInSeparateAppDomain(AppDomainSetup setup, Action action)
{
var dir = Path.GetDirectoryName(typeof(AppDomainUtils).Assembly.CodeBase).Replace("file:\\", "");
setup.PrivateBinPath = dir;
setup.ApplicationBase = dir;
setup.ApplicationName = Guid.NewGuid().ToString();
setup.ShadowCopyFiles = "true";
setup.ShadowCopyDirectories = setup.ApplicationBase;
setup.CachePath = Path.Combine(Path.GetTempPath(), setup.ApplicationName);
AppDomain appDomain = null;
try
{
appDomain = AppDomain.CreateDomain(setup.ApplicationName, null, setup);
AppDomainHelper helper = appDomain.CreateInstanceAndUnwrap(typeof(AppDomainUtils).Assembly.FullName, typeof(AppDomainHelper).FullName) as AppDomainHelper;
helper.Run(action);
}
finally
{
if (appDomain != null)
{
AppDomain.Unload(appDomain);
}
}
}
public class AppDomainHelper : MarshalByRefObject
{
public void Run(Action action)
{
action();
}
}
public static void SetPreAppStartStage()
{
var stage = typeof(BuildManager).GetProperty("PreStartInitStage", BindingFlags.Static | BindingFlags.NonPublic);
var value = ((FieldInfo)typeof(BuildManager).Assembly.GetType("System.Web.Compilation.PreStartInitStage").GetMember("DuringPreStartInit")[0]).GetValue(null);
stage.SetValue(null, value, new object[] { });
SetAppData();
var env = new HostingEnvironment();
}
public static void SetAppData()
{
var appdomain = AppDomain.CurrentDomain;
// Set some dummy values to make the appdomain seem more like a ASP.NET hosted one
appdomain.SetData(".appDomain", "*");
appdomain.SetData(".appId", "appId");
appdomain.SetData(".appPath", "appPath");
appdomain.SetData(".appVPath", "/WebSite1");
appdomain.SetData(".domainId", "1");
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon
{
// This extends xUnit.net's Assert class, and makes it partial so that we can
// organize the extension points by logical functionality (rather than dumping them
// all into this single file).
//
// See files named XxxAssertions for root extensions to Assert.
public partial class Assert : Xunit.Assert
{
public static readonly ReflectionAssert Reflection = new ReflectionAssert();
public static readonly TypeAssert Type = new TypeAssert();
public static readonly HttpAssert Http = new HttpAssert();
public static readonly MediaTypeAssert MediaType = new MediaTypeAssert();
public static readonly GenericTypeAssert GenericType = new GenericTypeAssert();
public static readonly SerializerAssert Serializer = new SerializerAssert();
public static readonly StreamAssert Stream = new StreamAssert();
public static readonly TaskAssert Task = new TaskAssert();
public static readonly XmlAssert Xml = new XmlAssert();
}
}

Просмотреть файл

@ -0,0 +1,72 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.Threading;
namespace Microsoft.TestCommon
{
public class CultureReplacer : IDisposable
{
private const string _defaultCultureName = "en-GB";
private const string _defaultUICultureName = "en-US";
private static readonly CultureInfo _defaultCulture = CultureInfo.GetCultureInfo(_defaultCultureName);
private readonly CultureInfo _originalCulture;
private readonly CultureInfo _originalUICulture;
private readonly long _threadId;
// Culture => Formatting of dates/times/money/etc, defaults to en-GB because en-US is the same as InvariantCulture
// We want to be able to find issues where the InvariantCulture is used, but a specific culture should be.
//
// UICulture => Language
public CultureReplacer(string culture = _defaultCultureName, string uiCulture = _defaultUICultureName)
{
_originalCulture = Thread.CurrentThread.CurrentCulture;
_originalUICulture = Thread.CurrentThread.CurrentUICulture;
_threadId = Thread.CurrentThread.ManagedThreadId;
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(uiCulture);
}
/// <summary>
/// The name of the culture that is used as the default value for Thread.CurrentCulture when CultureReplacer is used.
/// </summary>
public static string DefaultCultureName
{
get { return _defaultCultureName; }
}
/// <summary>
/// The name of the culture that is used as the default value for Thread.UICurrentCulture when CultureReplacer is used.
/// </summary>
public static string DefaultUICultureName
{
get { return _defaultUICultureName; }
}
/// <summary>
/// The culture that is used as the default value for Thread.CurrentCulture when CultureReplacer is used.
/// </summary>
public static CultureInfo DefaultCulture
{
get { return _defaultCulture; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
Assert.True(Thread.CurrentThread.ManagedThreadId == _threadId, "The current thread is not the same as the thread invoking the constructor. This should never happen.");
Thread.CurrentThread.CurrentCulture = _originalCulture;
Thread.CurrentThread.CurrentUICulture = _originalUICulture;
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class DataAttribute : Xunit.Extensions.DataAttribute
{
}
}

Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
namespace Microsoft.TestCommon
{
public class DictionaryEqualityComparer : IEqualityComparer<IDictionary<string, object>>
{
public bool Equals(IDictionary<string, object> x, IDictionary<string, object> y)
{
if (x.Count != y.Count)
{
return false;
}
foreach (string key in x.Keys)
{
object xVal = x[key];
object yVal;
if (!y.TryGetValue(key, out yVal))
{
return false;
}
if (xVal == null)
{
if (yVal == null)
{
continue;
}
return false;
}
if (!xVal.Equals(yVal))
{
return false;
}
}
return true;
}
public int GetHashCode(IDictionary<string, object> obj)
{
return 1;
}
}
}

Просмотреть файл

@ -0,0 +1,101 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
public abstract class EnumHelperTestBase<TEnum> where TEnum : IComparable, IFormattable, IConvertible
{
private Func<TEnum, bool> _isDefined;
private Action<TEnum, string> _validate;
private TEnum _undefined;
/// <summary>
/// Helper to verify that we validate enums correctly when passed as arguments etc.
/// </summary>
/// <param name="isDefined">A Func used to validate that a value is defined.</param>
/// <param name="validate">A Func used to validate that a value is definded of throw an exception.</param>
/// <param name="undefined">An undefined value.</param>
protected EnumHelperTestBase(Func<TEnum, bool> isDefined, Action<TEnum, string> validate, TEnum undefined)
{
_isDefined = isDefined;
_validate = validate;
_undefined = undefined;
}
[Fact]
public void IsDefined_ReturnsTrueForDefinedValues()
{
Array values = Enum.GetValues(typeof(TEnum));
foreach (object value in values)
{
if (ValueExistsForFramework((TEnum)value))
{
Assert.True(_isDefined((TEnum)value));
}
else
{
Assert.False(_isDefined((TEnum)value));
}
}
}
[Fact]
public void IsDefined_ReturnsFalseForUndefinedValues()
{
Assert.False(_isDefined(_undefined));
}
[Fact]
public void Validate_DoesNotThrowForDefinedValues()
{
Array values = Enum.GetValues(typeof(TEnum));
foreach (object value in values)
{
if (ValueExistsForFramework((TEnum)value))
{
_validate((TEnum)value, "parameter");
}
}
}
[Fact]
public void Validate_ThrowsForUndefinedValues()
{
AssertForUndefinedValue(
() => _validate(_undefined, "parameter"),
"parameter",
(int)Convert.ChangeType(_undefined, typeof(int)),
typeof(TEnum),
allowDerivedExceptions: false);
}
/// <summary>
/// Override this if InvalidEnumArgument is not supported in the targetted platform
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="invalidValue">The expected invalid value that should appear in the message</param>
/// <param name="enumType">The type of the enumeration</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
protected virtual void AssertForUndefinedValue(Action testCode, string parameterName, int invalidValue, Type enumType, bool allowDerivedExceptions = false)
{
Assert.ThrowsInvalidEnumArgument(
testCode,
parameterName,
invalidValue,
enumType,
allowDerivedExceptions);
}
/// <summary>
/// Override this to determine if a given enum value for an enum exists in a given framework
/// </summary>
/// <param name="value"></param>
/// <returns>Wheter the value exists</returns>
protected virtual bool ValueExistsForFramework(TEnum value)
{
return true;
}
}
}

Просмотреть файл

@ -0,0 +1,521 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
namespace Microsoft.TestCommon
{
public partial class Assert
{
/// <summary>
/// Verifies that the exact exception is thrown (and not a derived exception type).
/// </summary>
/// <typeparam name="T">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static T Throws<T>(Action testCode)
where T : Exception
{
return (T)Throws(typeof(T), testCode);
}
/// <summary>
/// Verifies that the exact exception is thrown (and not a derived exception type).
/// Generally used to test property accessors.
/// </summary>
/// <typeparam name="T">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static T Throws<T>(Func<object> testCode)
where T : Exception
{
return (T)Throws(typeof(T), testCode);
}
/// <summary>
/// Verifies that the exact exception is thrown (and not a derived exception type).
/// </summary>
/// <param name="exceptionType">The type of the exception expected to be thrown</param>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static Exception Throws(Type exceptionType, Action testCode)
{
Exception exception = RecordException(testCode);
return VerifyException(exceptionType, exception);
}
/// <summary>
/// Verifies that the exact exception is thrown (and not a derived exception type).
/// Generally used to test property accessors.
/// </summary>
/// <param name="exceptionType">The type of the exception expected to be thrown</param>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static Exception Throws(Type exceptionType, Func<object> testCode)
{
return Throws(exceptionType, () => { testCode(); });
}
/// <summary>
/// Verifies that an exception of the given type (or optionally a derived type) is thrown.
/// </summary>
/// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static TException Throws<TException>(Action testCode, bool allowDerivedExceptions)
where TException : Exception
{
Type exceptionType = typeof(TException);
Exception exception = RecordException(testCode);
TargetInvocationException tie = exception as TargetInvocationException;
if (tie != null)
{
exception = tie.InnerException;
}
if (exception == null)
{
throw new ThrowsException(exceptionType);
}
var typedException = exception as TException;
if (typedException == null || (!allowDerivedExceptions && typedException.GetType() != typeof(TException)))
{
throw new ThrowsException(exceptionType, exception);
}
return typedException;
}
/// <summary>
/// Verifies that an exception of the given type (or optionally a derived type) is thrown.
/// Generally used to test property accessors.
/// </summary>
/// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static TException Throws<TException>(Func<object> testCode, bool allowDerivedExceptions)
where TException : Exception
{
return Throws<TException>(() => { testCode(); }, allowDerivedExceptions);
}
/// <summary>
/// Verifies that an exception of the given type (or optionally a derived type) is thrown.
/// Also verifies that the exception message matches.
/// </summary>
/// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="exceptionMessage">The exception message to verify</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static TException Throws<TException>(Action testCode, string exceptionMessage, bool allowDerivedExceptions = false)
where TException : Exception
{
var ex = Throws<TException>(testCode, allowDerivedExceptions);
VerifyExceptionMessage(ex, exceptionMessage);
return ex;
}
/// <summary>
/// Verifies that an exception of the given type (or optionally a derived type) is thrown.
/// Also verified that the exception message matches.
/// </summary>
/// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="exceptionMessage">The exception message to verify</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static TException Throws<TException>(Func<object> testCode, string exceptionMessage, bool allowDerivedExceptions = false)
where TException : Exception
{
return Throws<TException>(() => { testCode(); }, exceptionMessage, allowDerivedExceptions);
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentException ThrowsArgument(Action testCode, string paramName, bool allowDerivedExceptions = false)
{
var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);
if (paramName != null)
{
Equal(paramName, ex.ParamName);
}
return ex;
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="exceptionMessage">The exception message to verify</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentException ThrowsArgument(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false)
{
var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);
if (paramName != null)
{
Equal(paramName, ex.ParamName);
}
VerifyExceptionMessage(ex, exceptionMessage, partialMatch: true);
return ex;
}
/// <summary>
/// Verifies that the code throws an ArgumentException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentException ThrowsArgument(Func<object> testCode, string paramName, bool allowDerivedExceptions = false)
{
var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);
if (paramName != null)
{
Equal(paramName, ex.ParamName);
}
return ex;
}
/// <summary>
/// Verifies that the code throws an ArgumentNullException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentNullException ThrowsArgumentNull(Action testCode, string paramName)
{
var ex = Throws<ArgumentNullException>(testCode, allowDerivedExceptions: false);
if (paramName != null)
{
Equal(paramName, ex.ParamName);
}
return ex;
}
/// <summary>
/// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot
/// be null or empty.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentException ThrowsArgumentNullOrEmpty(Action testCode, string paramName)
{
return Throws<ArgumentException>(testCode, "Value cannot be null or empty.\r\nParameter name: " + paramName, allowDerivedExceptions: false);
}
/// <summary>
/// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot
/// be null or empty string.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentException ThrowsArgumentNullOrEmptyString(Action testCode, string paramName)
{
return ThrowsArgument(testCode, paramName, "Value cannot be null or an empty string.", allowDerivedExceptions: true);
}
/// <summary>
/// Verifies that the code throws an ArgumentOutOfRangeException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="exceptionMessage">The exception message to verify</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <param name="actualValue">The actual value provided</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false, object actualValue = null)
{
if (exceptionMessage != null)
{
exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName;
if (actualValue != null)
{
exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue);
}
}
var ex = Throws<ArgumentOutOfRangeException>(testCode, exceptionMessage, allowDerivedExceptions);
if (paramName != null)
{
Equal(paramName, ex.ParamName);
}
return ex;
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
/// the value must be greater than the given <paramref name="value"/>.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="actualValue">The actual value provided.</param>
/// <param name="value">The expected limit value.</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentOutOfRangeException ThrowsArgumentGreaterThan(Action testCode, string paramName, string value, object actualValue = null)
{
return ThrowsArgumentOutOfRange(
testCode,
paramName,
String.Format(CultureReplacer.DefaultCulture, "Value must be greater than {0}.", value), false, actualValue);
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
/// the value must be greater than or equal to the given value.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="value">The expected limit value.</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentOutOfRangeException ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string value, object actualValue = null)
{
return ThrowsArgumentOutOfRange(
testCode,
paramName,
String.Format(CultureReplacer.DefaultCulture, "Value must be greater than or equal to {0}.", value), false, actualValue);
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
/// the value must be less than the given <paramref name="maxValue"/>.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="actualValue">The actual value provided.</param>
/// <param name="maxValue">The expected limit value.</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentOutOfRangeException ThrowsArgumentLessThan(Action testCode, string paramName, string maxValue, object actualValue = null)
{
return ThrowsArgumentOutOfRange(
testCode,
paramName,
String.Format(CultureReplacer.DefaultCulture, "Value must be less than {0}.", maxValue), false, actualValue);
}
/// <summary>
/// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
/// the value must be less than or equal to the given <paramref name="maxValue"/>.
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="actualValue">The actual value provided.</param>
/// <param name="maxValue">The expected limit value.</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string maxValue, object actualValue = null)
{
return ThrowsArgumentOutOfRange(
testCode,
paramName,
String.Format(CultureReplacer.DefaultCulture, "Value must be less than or equal to {0}.", maxValue), false, actualValue);
}
/// <summary>
/// Verifies that the code throws an HttpException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="exceptionMessage">The exception message to verify</param>
/// <param name="httpCode">The expected HTTP status code of the exception</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static HttpException ThrowsHttpException(Action testCode, string exceptionMessage, int httpCode, bool allowDerivedExceptions = false)
{
var ex = Throws<HttpException>(testCode, exceptionMessage, allowDerivedExceptions);
Equal(httpCode, ex.GetHttpCode());
return ex;
}
/// <summary>
/// Verifies that the code throws an InvalidEnumArgumentException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="paramName">The name of the parameter that should throw the exception</param>
/// <param name="invalidValue">The expected invalid value that should appear in the message</param>
/// <param name="enumType">The type of the enumeration</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static InvalidEnumArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false)
{
string message = String.Format(CultureReplacer.DefaultCulture,
"The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}",
paramName, invalidValue, enumType.Name, Environment.NewLine);
return Throws<InvalidEnumArgumentException>(testCode, message, allowDerivedExceptions);
}
/// <summary>
/// Verifies that the code throws an HttpException (or optionally any exception which derives from it).
/// </summary>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <param name="objectName">The name of the object that was dispose</param>
/// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
public static ObjectDisposedException ThrowsObjectDisposed(Action testCode, string objectName, bool allowDerivedExceptions = false)
{
var ex = Throws<ObjectDisposedException>(testCode, allowDerivedExceptions);
if (objectName != null)
{
Equal(objectName, ex.ObjectName);
}
return ex;
}
/// <summary>
/// Verifies that an exception of the given type is thrown.
/// </summary>
/// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The exception that was thrown, when successful</returns>
/// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
/// <remarks>
/// Unlike other Throws* methods, this method does not enforce running the exception delegate with a known Thread Culture.
/// </remarks>
public static async Task<TException> ThrowsAsync<TException>(Func<Task> testCode)
where TException : Exception
{
Exception exception = null;
try
{
// The 'testCode' Task might execute asynchronously in a different thread making it hard to enforce the thread culture.
// The correct way to verify exception messages in such a scenario would be to run the task synchronously inside of a
// culture enforced block.
await testCode();
}
catch (Exception ex)
{
exception = ex;
}
VerifyException(typeof(TException), exception);
return (TException)exception;
}
// We've re-implemented all the xUnit.net Throws code so that we can get this
// updated implementation of RecordException which silently unwraps any instances
// of AggregateException. In addition to unwrapping exceptions, this method ensures
// that tests are executed in with a known set of Culture and UICulture. This prevents
// tests from failing when executed on a non-English machine.
private static Exception RecordException(Action testCode)
{
try
{
using (new CultureReplacer())
{
testCode();
}
return null;
}
catch (Exception exception)
{
return UnwrapException(exception);
}
}
private static Exception UnwrapException(Exception exception)
{
AggregateException aggEx = exception as AggregateException;
if (aggEx != null)
{
return aggEx.GetBaseException();
}
return exception;
}
private static Exception VerifyException(Type exceptionType, Exception exception)
{
if (exception == null)
{
throw new ThrowsException(exceptionType);
}
else if (exceptionType != exception.GetType())
{
throw new ThrowsException(exceptionType, exception);
}
return exception;
}
private static void VerifyExceptionMessage(Exception exception, string expectedMessage, bool partialMatch = false)
{
if (expectedMessage != null)
{
if (!partialMatch)
{
Equal(expectedMessage, exception.Message);
}
else
{
Contains(expectedMessage, exception.Message);
}
}
}
// Custom ThrowsException so we can filter the stack trace.
[Serializable]
private class ThrowsException : Xunit.Sdk.ThrowsException
{
public ThrowsException(Type type) : base(type) { }
public ThrowsException(Type type, Exception ex) : base(type, ex) { }
protected override bool ExcludeStackFrame(string stackFrame)
{
if (stackFrame.StartsWith("at Microsoft.TestCommon.Assert.", StringComparison.OrdinalIgnoreCase))
{
return true;
}
return base.ExcludeStackFrame(stackFrame);
}
}
}
}

Просмотреть файл

@ -0,0 +1,60 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Xunit.Sdk;
namespace Microsoft.TestCommon
{
/// <summary>
/// An override of <see cref="FactAttribute"/> that provides extended capabilities.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class FactAttribute : Xunit.FactAttribute
{
public FactAttribute()
{
Timeout = Debugger.IsAttached ? Int32.MaxValue : TimeoutConstant.DefaultTimeout;
Platforms = Platform.All;
PlatformJustification = "Unsupported platform (test runs on {0}, current platform is {1})";
}
/// <summary>
/// Gets the platform that the unit test is currently running on.
/// </summary>
protected Platform Platform
{
get { return PlatformInfo.Platform; }
}
/// <summary>
/// Gets or set the platforms that the unit test is compatible with. Defaults to
/// <see cref="Platform.All"/>.
/// </summary>
public Platform Platforms { get; set; }
/// <summary>
/// Gets or sets the platform skipping justification. This message can receive
/// the supported platforms as {0}, and the current platform as {1}.
/// </summary>
public string PlatformJustification { get; set; }
/// <inheritdoc/>
protected override IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo method)
{
if ((Platforms & Platform) == 0)
{
return new[] {
new SkipCommand(
method,
DisplayName,
String.Format(PlatformJustification, Platforms.ToString().Replace(", ", " | "), Platform)
)
};
}
return base.EnumerateTestCommands(method);
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Reflection;
namespace Microsoft.TestCommon
{
public class ForceGCAttribute : Xunit.BeforeAfterTestAttribute
{
public override void After(MethodInfo methodUnderTest)
{
GC.Collect(99);
GC.Collect(99);
GC.Collect(99);
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class InlineDataAttribute : Xunit.Extensions.InlineDataAttribute
{
public InlineDataAttribute(params object[] dataValues)
: base(dataValues)
{
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
namespace Microsoft.TestCommon
{
public class MatrixTheoryDataSet<T1, T2> : TheoryDataSet<T1, T2>
{
public MatrixTheoryDataSet(IEnumerable<T1> data1, IEnumerable<T2> data2)
{
Contract.Assert(data1 != null && data1.Any());
Contract.Assert(data2 != null && data2.Any());
foreach (T1 t1 in data1)
{
foreach (T2 t2 in data2)
{
Add(t1, t2);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,383 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Microsoft.TestCommon;
namespace System.Web.TestUtil
{
public static class MemberHelper
{
private static ConstructorInfo GetConstructorInfo(object instance, Type[] parameterTypes)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
ConstructorInfo constructorInfo = instance.GetType().GetConstructor(parameterTypes);
if (constructorInfo == null)
{
throw new ArgumentException(String.Format(
"A matching constructor on type '{0}' could not be found.",
instance.GetType().FullName));
}
return constructorInfo;
}
private static EventInfo GetEventInfo(object instance, string eventName)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (String.IsNullOrEmpty(eventName))
{
throw new ArgumentException("An event must be specified.", "eventName");
}
EventInfo eventInfo = instance.GetType().GetEvent(eventName);
if (eventInfo == null)
{
throw new ArgumentException(String.Format(
"An event named '{0}' on type '{1}' could not be found.",
eventName, instance.GetType().FullName));
}
return eventInfo;
}
private static MethodInfo GetMethodInfo(object instance, string methodName, Type[] types = null, MethodAttributes attrs = MethodAttributes.Public)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (String.IsNullOrEmpty(methodName))
{
throw new ArgumentException("A method must be specified.", "methodName");
}
MethodInfo methodInfo;
if (types != null)
{
methodInfo = instance.GetType().GetMethod(methodName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
types,
null);
}
else
{
methodInfo = instance.GetType().GetMethod(methodName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (methodInfo == null)
{
throw new ArgumentException(String.Format(
"A method named '{0}' on type '{1}' could not be found.",
methodName, instance.GetType().FullName));
}
if ((methodInfo.Attributes & attrs) != attrs)
{
throw new ArgumentException(String.Format(
"Method '{0}' on type '{1}' with attributes '{2}' does not match the attributes '{3}'.",
methodName, instance.GetType().FullName, methodInfo.Attributes, attrs));
}
return methodInfo;
}
private static PropertyInfo GetPropertyInfo(object instance, string propertyName)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (String.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("A property must be specified.", "propertyName");
}
PropertyInfo propInfo = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (propInfo == null)
{
throw new ArgumentException(String.Format(
"A property named '{0}' on type '{1}' could not be found.",
propertyName, instance.GetType().FullName));
}
return propInfo;
}
private static void TestAttribute<TAttribute>(MemberInfo memberInfo, TAttribute attributeValue)
where TAttribute : Attribute
{
object[] attrs = memberInfo.GetCustomAttributes(typeof(TAttribute), true);
if (attributeValue == null)
{
Assert.True(attrs.Length == 0, "Member should not have an attribute of type " + typeof(TAttribute));
}
else
{
Assert.True(attrs != null && attrs.Length > 0,
"Member does not have an attribute of type " + typeof(TAttribute));
Assert.Equal(attributeValue, attrs[0]);
}
}
public static void TestBooleanProperty(object instance, string propertyName, bool initialValue, bool testDefaultValue)
{
// Assert initial value
TestGetPropertyValue(instance, propertyName, initialValue);
if (testDefaultValue)
{
// Assert DefaultValue attribute matches inital value
TestDefaultValue(instance, propertyName);
}
TestPropertyValue(instance, propertyName, true);
TestPropertyValue(instance, propertyName, false);
}
public static void TestDefaultValue(object instance, string propertyName)
{
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
object initialValue = propInfo.GetValue(instance, null);
TestAttribute(propInfo, new DefaultValueAttribute(initialValue));
}
public static void TestEvent<TEventArgs>(object instance, string eventName, TEventArgs eventArgs) where TEventArgs : EventArgs
{
EventInfo eventInfo = GetEventInfo(instance, eventName);
// Assert category "Action"
TestAttribute(eventInfo, new CategoryAttribute("Action"));
// Call protected method with no event handlers, assert no error
MethodInfo methodInfo = GetMethodInfo(instance, "On" + eventName, attrs: MethodAttributes.Family | MethodAttributes.Virtual);
methodInfo.Invoke(instance, new object[] { eventArgs });
// Attach handler, call method, assert fires once
List<object> eventHandlerArgs = new List<object>();
EventHandler<TEventArgs> handler = new EventHandler<TEventArgs>(delegate(object sender, TEventArgs t)
{
eventHandlerArgs.Add(sender);
eventHandlerArgs.Add(t);
});
eventInfo.AddEventHandler(instance, handler);
methodInfo.Invoke(instance, new object[] { eventArgs });
Assert.Equal(new[] { instance, eventArgs }, eventHandlerArgs.ToArray());
// Detach handler, call method, assert not fired
eventHandlerArgs = new List<object>();
eventInfo.RemoveEventHandler(instance, handler);
methodInfo.Invoke(instance, new object[] { eventArgs });
Assert.Empty(eventHandlerArgs);
}
public static void TestGetPropertyValue(object instance, string propertyName, object valueToCheck)
{
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
object value = propInfo.GetValue(instance, null);
Assert.Equal(valueToCheck, value);
}
public static void TestEnumProperty<TEnumValue>(object instance, string propertyName, TEnumValue initialValue, bool testDefaultValue)
{
// Assert initial value
TestGetPropertyValue(instance, propertyName, initialValue);
if (testDefaultValue)
{
// Assert DefaultValue attribute matches inital value
TestDefaultValue(instance, propertyName);
}
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
// Values are sorted numerically
TEnumValue[] values = (TEnumValue[])Enum.GetValues(propInfo.PropertyType);
// Assert get/set works for all valid enum values
foreach (TEnumValue value in values)
{
TestPropertyValue(instance, propertyName, value);
}
// Assert ArgumentOutOfRangeException is thrown for value one less than smallest
// enum value, and one more than largest enum value
var targetException = Assert.Throws<TargetInvocationException>(() => propInfo.SetValue(instance, Convert.ToInt32(values[0]) - 1, null));
Assert.IsType<ArgumentOutOfRangeException>(targetException.InnerException);
targetException = Assert.Throws<TargetInvocationException>(() => propInfo.SetValue(instance, Convert.ToInt32(values[values.Length - 1]) + 1, null));
Assert.IsType<ArgumentOutOfRangeException>(targetException.InnerException);
}
public static void TestInt32Property(object instance, string propertyName, int value1, int value2)
{
TestPropertyValue(instance, propertyName, value1);
TestPropertyValue(instance, propertyName, value2);
}
public static void TestPropertyWithDefaultInstance(object instance, string propertyName, object valueToSet)
{
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
// Set to explicit property
propInfo.SetValue(instance, valueToSet, null);
object value = propInfo.GetValue(instance, null);
Assert.Equal(valueToSet, value);
// Set to null
propInfo.SetValue(instance, null, null);
value = propInfo.GetValue(instance, null);
Assert.IsAssignableFrom(propInfo.PropertyType, value);
}
public static void TestPropertyWithDefaultInstance(object instance, string propertyName, object valueToSet, object defaultValue)
{
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
// Set to explicit property
propInfo.SetValue(instance, valueToSet, null);
object value = propInfo.GetValue(instance, null);
Assert.Same(valueToSet, value);
// Set to null
propInfo.SetValue(instance, null, null);
value = propInfo.GetValue(instance, null);
Assert.Equal(defaultValue, value);
}
public static void TestPropertyValue(object instance, string propertyName, object value)
{
TestPropertyValue(instance, propertyName, value, value);
}
public static void TestPropertyValue(object instance, string propertyName, object valueToSet, object valueToCheck)
{
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
propInfo.SetValue(instance, valueToSet, null);
object value = propInfo.GetValue(instance, null);
Assert.Equal(valueToCheck, value);
}
public static void TestStringParams(object instance, Type[] constructorParameterTypes, object[] parameters)
{
ConstructorInfo ctor = GetConstructorInfo(instance, constructorParameterTypes);
TestStringParams(ctor, instance, parameters);
}
public static void TestStringParams(object instance, string methodName, object[] parameters)
{
TestStringParams(instance, methodName, null, parameters);
}
public static void TestStringParams(object instance, string methodName, Type[] types, object[] parameters)
{
MethodInfo method = GetMethodInfo(instance, methodName, types);
TestStringParams(method, instance, parameters);
}
private static void TestStringParams(MethodBase method, object instance, object[] parameters)
{
ParameterInfo[] parameterInfos = method.GetParameters();
foreach (ParameterInfo parameterInfo in parameterInfos)
{
if (parameterInfo.ParameterType == typeof(String))
{
object originalParameter = parameters[parameterInfo.Position];
parameters[parameterInfo.Position] = null;
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
method.Invoke(instance, parameters);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
parameterInfo.Name);
parameters[parameterInfo.Position] = String.Empty;
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
method.Invoke(instance, parameters);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
parameterInfo.Name);
parameters[parameterInfo.Position] = originalParameter;
}
}
}
public static void TestStringProperty(object instance, string propertyName, string initialValue,
bool testDefaultValueAttribute = false, bool allowNullAndEmpty = true,
string nullAndEmptyReturnValue = "")
{
// Assert initial value
TestGetPropertyValue(instance, propertyName, initialValue);
if (testDefaultValueAttribute)
{
// Assert DefaultValue attribute matches inital value
TestDefaultValue(instance, propertyName);
}
if (allowNullAndEmpty)
{
// Assert get/set works for null
TestPropertyValue(instance, propertyName, null, nullAndEmptyReturnValue);
// Assert get/set works for String.Empty
TestPropertyValue(instance, propertyName, String.Empty, nullAndEmptyReturnValue);
}
else
{
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
TestPropertyValue(instance, propertyName, null);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
"value");
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
TestPropertyValue(instance, propertyName, String.Empty);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
"value");
}
// Assert get/set works for arbitrary value
TestPropertyValue(instance, propertyName, "TestValue");
}
}
}

Просмотреть файл

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),WebApiOData.sln))\tools\WebStack.settings.targets" />
<PropertyGroup>
<ProjectGuid>{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.TestCommon</RootNamespace>
<AssemblyName>Microsoft.TestCommon</AssemblyName>
<OutputPath>..\..\bin\$(Configuration)\Test\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="xunit, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\xunit.1.9.1\lib\net20\xunit.dll</HintPath>
</Reference>
<Reference Include="xunit.extensions, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="DataAttribute.cs" />
<Compile Include="EnumHelperTestBase.cs" />
<Compile Include="InlineDataAttribute.cs" />
<Compile Include="MatrixTheoryDataSet.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\TestDataHolder.cs" />
<Compile Include="Microsoft\TestCommon\Types\ByteEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\SByteEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\ShortEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\UIntEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\UShortEnum.cs" />
<Compile Include="Platform.cs" />
<Compile Include="PlatformInfo.cs" />
<Compile Include="PortReserver.cs" />
<Compile Include="PropertyDataAttribute.cs" />
<Compile Include="ReplaceCultureAttribute.cs" />
<Compile Include="RestoreThreadPrincipalAttribute.cs" />
<Compile Include="AppDomainUtils.cs" />
<Compile Include="Assert.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="CultureReplacer.cs" />
<Compile Include="FactAttribute.cs" />
<Compile Include="StringAssertions.cs" />
<Compile Include="StringAssertException.cs" />
<Compile Include="TheoryAttribute.cs" />
<Compile Include="DictionaryEqualityComparer.cs" />
<Compile Include="ExceptionAssertions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ForceGCAttribute.cs" />
<Compile Include="MemberHelper.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\RefTypeTestData.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\TestDataVariations.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\ValueTypeTestData.cs" />
<Compile Include="Microsoft\TestCommon\GenericTypeAssert.cs" />
<Compile Include="Microsoft\TestCommon\HttpAssert.cs" />
<Compile Include="Microsoft\TestCommon\MediaTypeAssert.cs" />
<Compile Include="Microsoft\TestCommon\MediaTypeHeaderValueComparer.cs" />
<Compile Include="Microsoft\TestCommon\ParsedMediaTypeHeaderValue.cs" />
<Compile Include="Microsoft\TestCommon\RegexReplacement.cs" />
<Compile Include="Microsoft\TestCommon\RuntimeEnvironment.cs" />
<Compile Include="Microsoft\TestCommon\SerializerAssert.cs" />
<Compile Include="Microsoft\TestCommon\StreamAssert.cs" />
<Compile Include="Microsoft\TestCommon\TaskAssert.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\TestData.cs" />
<Compile Include="Microsoft\TestCommon\TestDataSetAttribute.cs" />
<Compile Include="Microsoft\TestCommon\TimeoutConstant.cs" />
<Compile Include="Microsoft\TestCommon\TypeAssert.cs" />
<Compile Include="Microsoft\TestCommon\Types\FlagsEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\INameAndIdContainer.cs" />
<Compile Include="Microsoft\TestCommon\Types\ISerializableType.cs" />
<Compile Include="Microsoft\TestCommon\Types\LongEnum.cs" />
<Compile Include="Microsoft\TestCommon\Types\SimpleEnum.cs" />
<Compile Include="Microsoft\TestCommon\DataSets\CommonUnitTestDataSets.cs" />
<Compile Include="Microsoft\TestCommon\XmlAssert.cs" />
<Compile Include="PreAppStartTestHelper.cs" />
<Compile Include="PreserveSyncContextAttribute.cs" />
<Compile Include="ReflectionAssert.cs" />
<Compile Include="TaskExtensions.cs" />
<Compile Include="TestFile.cs" />
<Compile Include="TestHelper.cs" />
<Compile Include="TheoryDataSet.cs" />
<Compile Include="ThreadPoolSyncContext.cs" />
<Compile Include="TraitAttribute.cs" />
<Compile Include="VersionTestHelper.cs" />
<Compile Include="WebUtils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.ObjectModel;
using Microsoft.TestCommon.Types;
namespace Microsoft.TestCommon
{
public class CommonUnitTestDataSets
{
public static ValueTypeTestData<char> Chars { get { return TestData.CharTestData; } }
public static ValueTypeTestData<int> Ints { get { return TestData.IntTestData; } }
public static ValueTypeTestData<uint> Uints { get { return TestData.UintTestData; } }
public static ValueTypeTestData<short> Shorts { get { return TestData.ShortTestData; } }
public static ValueTypeTestData<ushort> Ushorts { get { return TestData.UshortTestData; } }
public static ValueTypeTestData<long> Longs { get { return TestData.LongTestData; } }
public static ValueTypeTestData<ulong> Ulongs { get { return TestData.UlongTestData; } }
public static ValueTypeTestData<byte> Bytes { get { return TestData.ByteTestData; } }
public static ValueTypeTestData<sbyte> SBytes { get { return TestData.SByteTestData; } }
public static ValueTypeTestData<bool> Bools { get { return TestData.BoolTestData; } }
public static ValueTypeTestData<double> Doubles { get { return TestData.DoubleTestData; } }
public static ValueTypeTestData<float> Floats { get { return TestData.FloatTestData; } }
public static ValueTypeTestData<DateTime> DateTimes { get { return TestData.DateTimeTestData; } }
public static ValueTypeTestData<Decimal> Decimals { get { return TestData.DecimalTestData; } }
public static ValueTypeTestData<TimeSpan> TimeSpans { get { return TestData.TimeSpanTestData; } }
public static ValueTypeTestData<Guid> Guids { get { return TestData.GuidTestData; } }
public static ValueTypeTestData<DateTimeOffset> DateTimeOffsets { get { return TestData.DateTimeOffsetTestData; } }
public static ValueTypeTestData<SimpleEnum> SimpleEnums { get { return TestData.SimpleEnumTestData; } }
public static ValueTypeTestData<LongEnum> LongEnums { get { return TestData.LongEnumTestData; } }
public static ValueTypeTestData<FlagsEnum> FlagsEnums { get { return TestData.FlagsEnumTestData; } }
public static TestData<string> EmptyStrings { get { return TestData.EmptyStrings; } }
public static RefTypeTestData<string> Strings { get { return TestData.StringTestData; } }
public static TestData<string> NonNullEmptyStrings { get { return TestData.NonNullEmptyStrings; } }
public static RefTypeTestData<ISerializableType> ISerializableTypes { get { return TestData.ISerializableTypeTestData; } }
public static ReadOnlyCollection<TestData> ValueTypeTestDataCollection { get { return TestData.ValueTypeTestDataCollection; } }
public static ReadOnlyCollection<TestData> RefTypeTestDataCollection { get { return TestData.RefTypeTestDataCollection; } }
public static ReadOnlyCollection<TestData> ValueAndRefTypeTestDataCollection { get { return TestData.ValueAndRefTypeTestDataCollection; } }
public static ReadOnlyCollection<TestData> RepresentativeValueAndRefTypeTestDataCollection { get { return TestData.RepresentativeValueAndRefTypeTestDataCollection; } }
}
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.TestCommon
{
public class RefTypeTestData<T> : TestData<T> where T : class
{
private Func<IEnumerable<T>> testDataProvider;
private Func<IEnumerable<T>> derivedTypeTestDataProvider;
private Func<IEnumerable<T>> knownTypeTestDataProvider;
public RefTypeTestData(Func<IEnumerable<T>> testDataProvider)
{
if (testDataProvider == null)
{
throw new ArgumentNullException("testDataProvider");
}
this.testDataProvider = testDataProvider;
this.RegisterTestDataVariation(TestDataVariations.WithNull, this.Type, GetNullTestData);
}
public RefTypeTestData(
Func<IEnumerable<T>> testDataProvider,
Func<IEnumerable<T>> derivedTypeTestDataProvider,
Func<IEnumerable<T>> knownTypeTestDataProvider)
: this(testDataProvider)
{
this.derivedTypeTestDataProvider = derivedTypeTestDataProvider;
if (this.derivedTypeTestDataProvider != null)
{
this.RegisterTestDataVariation(TestDataVariations.AsDerivedType, this.Type, this.GetTestDataAsDerivedType);
}
this.knownTypeTestDataProvider = knownTypeTestDataProvider;
if (this.knownTypeTestDataProvider != null)
{
this.RegisterTestDataVariation(TestDataVariations.AsKnownType, this.Type, this.GetTestDataAsDerivedKnownType);
}
}
public T GetNullTestData()
{
return null;
}
public IEnumerable<T> GetTestDataAsDerivedType()
{
if (this.derivedTypeTestDataProvider != null)
{
return this.derivedTypeTestDataProvider();
}
return Enumerable.Empty<T>();
}
public IEnumerable<T> GetTestDataAsDerivedKnownType()
{
if (this.knownTypeTestDataProvider != null)
{
return this.knownTypeTestDataProvider();
}
return Enumerable.Empty<T>();
}
protected override IEnumerable<T> GetTypedTestData()
{
return this.testDataProvider();
}
}
}

Просмотреть файл

@ -0,0 +1,463 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.TestCommon.Types;
namespace Microsoft.TestCommon
{
/// <summary>
/// A base class for test data. A <see cref="TestData"/> instance is associated with a given type, and the <see cref="TestData"/> instance can
/// provide instances of the given type to use as data in tests. The same <see cref="TestData"/> instance can also provide instances
/// of types related to the given type, such as a <see cref="List<>"/> of the type. See the <see cref="TestDataVariations"/> enum for all the
/// variations of test data that a <see cref="TestData"/> instance can provide.
/// </summary>
public abstract class TestData
{
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="char"/>.
/// </summary>
public static readonly ValueTypeTestData<char> CharTestData = new ValueTypeTestData<char>('a', Char.MinValue, Char.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="int"/>.
/// </summary>
public static readonly ValueTypeTestData<int> IntTestData = new ValueTypeTestData<int>(-1, 0, 1, Int32.MinValue, Int32.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="uint"/>.
/// </summary>
public static readonly ValueTypeTestData<uint> UintTestData = new ValueTypeTestData<uint>(0, 1, UInt32.MinValue, UInt32.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="short"/>.
/// </summary>
public static readonly ValueTypeTestData<short> ShortTestData = new ValueTypeTestData<short>(-1, 0, 1, Int16.MinValue, Int16.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="ushort"/>.
/// </summary>
public static readonly ValueTypeTestData<ushort> UshortTestData = new ValueTypeTestData<ushort>(0, 1, UInt16.MinValue, UInt16.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="long"/>.
/// </summary>
public static readonly ValueTypeTestData<long> LongTestData = new ValueTypeTestData<long>(-1, 0, 1, Int64.MinValue, Int64.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="ulong"/>.
/// </summary>
public static readonly ValueTypeTestData<ulong> UlongTestData = new ValueTypeTestData<ulong>(0, 1, UInt64.MinValue, UInt64.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="byte"/>.
/// </summary>
public static readonly ValueTypeTestData<byte> ByteTestData = new ValueTypeTestData<byte>(0, 1, Byte.MinValue, Byte.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="sbyte"/>.
/// </summary>
public static readonly ValueTypeTestData<sbyte> SByteTestData = new ValueTypeTestData<sbyte>(-1, 0, 1, SByte.MinValue, SByte.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="bool"/>.
/// </summary>
public static readonly ValueTypeTestData<bool> BoolTestData = new ValueTypeTestData<bool>(true, false);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="double"/>.
/// </summary>
public static readonly ValueTypeTestData<double> DoubleTestData = new ValueTypeTestData<double>(
-1.0,
0.0,
1.0,
double.MinValue,
double.MaxValue,
double.PositiveInfinity,
double.NegativeInfinity);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="float"/>.
/// </summary>
public static readonly ValueTypeTestData<float> FloatTestData = new ValueTypeTestData<float>(
-1.0f,
0.0f,
1.0f,
float.MinValue,
float.MaxValue,
float.PositiveInfinity,
float.NegativeInfinity);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="decimal"/>.
/// </summary>
public static readonly ValueTypeTestData<decimal> DecimalTestData = new ValueTypeTestData<decimal>(
-1M,
0M,
1M,
decimal.MinValue,
decimal.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="DateTime"/>.
/// </summary>
public static readonly ValueTypeTestData<DateTime> DateTimeTestData = new ValueTypeTestData<DateTime>(
DateTime.Now,
DateTime.UtcNow,
DateTime.MaxValue,
DateTime.MinValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="TimeSpan"/>.
/// </summary>
public static readonly ValueTypeTestData<TimeSpan> TimeSpanTestData = new ValueTypeTestData<TimeSpan>(
TimeSpan.MinValue,
TimeSpan.MaxValue);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="Guid"/>.
/// </summary>
public static readonly ValueTypeTestData<Guid> GuidTestData = new ValueTypeTestData<Guid>(
Guid.NewGuid(),
Guid.Empty);
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="DateTimeOffset"/>.
/// </summary>
public static readonly ValueTypeTestData<DateTimeOffset> DateTimeOffsetTestData = new ValueTypeTestData<DateTimeOffset>(
DateTimeOffset.MaxValue,
DateTimeOffset.MinValue,
new DateTimeOffset(DateTime.Now));
/// <summary>
/// Common <see cref="TestData"/> for an <c>enum</c>.
/// </summary>
public static readonly ValueTypeTestData<SimpleEnum> SimpleEnumTestData = new ValueTypeTestData<SimpleEnum>(
SimpleEnum.First,
SimpleEnum.Second,
SimpleEnum.Third);
/// <summary>
/// Common <see cref="TestData"/> for an <c>enum</c> implemented with a <see cref="long"/>.
/// </summary>
public static readonly ValueTypeTestData<LongEnum> LongEnumTestData = new ValueTypeTestData<LongEnum>(
LongEnum.FirstLong,
LongEnum.SecondLong,
LongEnum.ThirdLong);
/// <summary>
/// Common <see cref="TestData"/> for an <c>enum</c> decorated with a <see cref="FlagsAttribtute"/>.
/// </summary>
public static readonly ValueTypeTestData<FlagsEnum> FlagsEnumTestData = new ValueTypeTestData<FlagsEnum>(
FlagsEnum.One,
FlagsEnum.Two,
FlagsEnum.Four);
/// <summary>
/// Expected permutations of non supported file paths.
/// </summary>
public static readonly TestData<string> NotSupportedFilePaths = new RefTypeTestData<string>(() => new List<string>() {
"cc:\\a\\b",
});
/// <summary>
/// Expected permutations of invalid file paths.
/// </summary>
public static readonly TestData<string> InvalidNonNullFilePaths = new RefTypeTestData<string>(() => new List<string>() {
String.Empty,
"",
" ",
" ",
"\t\t \n ",
"c:\\a<b",
"c:\\a>b",
"c:\\a\"b",
"c:\\a\tb",
"c:\\a|b",
"c:\\a\bb",
"c:\\a\0b",
});
/// <summary>
/// All expected permutations of an empty string.
/// </summary>
public static readonly TestData<string> NonNullEmptyStrings = new RefTypeTestData<string>(() => new List<string>() { String.Empty, "", " ", "\t\r\n" });
/// <summary>
/// All expected permutations of an empty string.
/// </summary>
public static readonly TestData<string> EmptyStrings = new RefTypeTestData<string>(() => new List<string>() { null, String.Empty, "", " ", "\t\r\n" });
/// <summary>
/// Common <see cref="TestData"/> for a <see cref="string"/>.
/// </summary>
public static readonly RefTypeTestData<string> StringTestData = new RefTypeTestData<string>(() => new List<string>() {
"",
" ", // one space
" ", // multiple spaces
" data ", // leading and trailing whitespace
"\t\t \n ",
"Some String!"});
/// <summary>
/// Common <see cref="TestData"/> for a class that implements <see cref="ISerializable"/>.
/// </summary>
public static readonly RefTypeTestData<ISerializableType> ISerializableTypeTestData = new RefTypeTestData<ISerializableType>(
ISerializableType.GetTestData);
/// <summary>
/// A read-only collection of value type test data.
/// </summary>
public static readonly ReadOnlyCollection<TestData> ValueTypeTestDataCollection = new ReadOnlyCollection<TestData>(new TestData[] {
CharTestData,
IntTestData,
UintTestData,
ShortTestData,
UshortTestData,
LongTestData,
UlongTestData,
ByteTestData,
SByteTestData,
BoolTestData,
DoubleTestData,
FloatTestData,
DecimalTestData,
TimeSpanTestData,
GuidTestData,
DateTimeOffsetTestData,
SimpleEnumTestData,
LongEnumTestData,
FlagsEnumTestData});
/// <summary>
/// A read-only collection of reference type test data.
/// </summary>
public static readonly ReadOnlyCollection<TestData> RefTypeTestDataCollection = new ReadOnlyCollection<TestData>(new TestData[] {
StringTestData,
ISerializableTypeTestData});
/// <summary>
/// A read-only collection of value and reference type test data.
/// </summary>
public static readonly ReadOnlyCollection<TestData> ValueAndRefTypeTestDataCollection = new ReadOnlyCollection<TestData>(
ValueTypeTestDataCollection.Concat(RefTypeTestDataCollection).ToList());
/// <summary>
/// A read-only collection of representative values and reference type test data.
/// Uses where exhaustive coverage is not required.
/// </summary>
public static readonly ReadOnlyCollection<TestData> RepresentativeValueAndRefTypeTestDataCollection = new ReadOnlyCollection<TestData>(new TestData[] {
IntTestData,
BoolTestData,
SimpleEnumTestData,
StringTestData,
});
private Dictionary<TestDataVariations, TestDataVariationProvider> registeredTestDataVariations;
/// <summary>
/// Initializes a new instance of the <see cref="TestData"/> class.
/// </summary>
/// <param name="type">The type associated with the <see cref="TestData"/> instance.</param>
protected TestData(Type type)
{
if (type.ContainsGenericParameters)
{
throw new InvalidOperationException("Only closed generic types are supported.");
}
this.Type = type;
this.registeredTestDataVariations = new Dictionary<TestDataVariations, TestDataVariationProvider>();
}
/// <summary>
/// Gets the type associated with the <see cref="TestData"/> instance.
/// </summary>
public Type Type { get; private set; }
/// <summary>
/// Gets the supported test data variations.
/// </summary>
/// <returns></returns>
public IEnumerable<TestDataVariations> GetSupportedTestDataVariations()
{
return this.registeredTestDataVariations.Keys;
}
/// <summary>
/// Gets the related type for the given test data variation or returns null if the <see cref="TestData"/> instance
/// doesn't support the given variation.
/// </summary>
/// <param name="variation">The test data variation with which to create the related <see cref="Type"/>.</param>
/// <returns>The related <see cref="Type"/> for the <see cref="TestData.Type"/> as given by the test data variation.</returns>
/// <example>
/// For example, if the given <see cref="TestData"/> was created for <see cref="string"/> test data and the varation parameter
/// was <see cref="TestDataVariations.AsList"/> then the returned type would be <see cref="List<string>"/>.
/// </example>
public Type GetAsTypeOrNull(TestDataVariations variation)
{
TestDataVariationProvider testDataVariation = null;
if (this.registeredTestDataVariations.TryGetValue(variation, out testDataVariation))
{
return testDataVariation.Type;
}
return null;
}
/// <summary>
/// Gets test data for the given test data variation or returns null if the <see cref="TestData"/> instance
/// doesn't support the given variation.
/// </summary>
/// <param name="variation">The test data variation with which to create the related test data.</param>
/// <returns>Test data of the type specified by the <see cref="TestData.GetAsTypeOrNull"/> method.</returns>
public object GetAsTestDataOrNull(TestDataVariations variation)
{
TestDataVariationProvider testDataVariation = null;
if (this.registeredTestDataVariations.TryGetValue(variation, out testDataVariation))
{
return testDataVariation.TestDataProvider();
}
return null;
}
/// <summary>
/// Allows derived classes to register a <paramref name="testDataProvider "/> <see cref="Func<>"/> that will
/// provide test data for a given variation.
/// </summary>
/// <param name="variation">The variation with which to register the <paramref name="testDataProvider "/>r.</param>
/// <param name="type">The type of the test data created by the <paramref name="testDataProvider "/></param>
/// <param name="testDataProvider">A <see cref="Func<>"/> that will provide test data.</param>
protected void RegisterTestDataVariation(TestDataVariations variation, Type type, Func<object> testDataProvider)
{
this.registeredTestDataVariations.Add(variation, new TestDataVariationProvider(type, testDataProvider));
}
private class TestDataVariationProvider
{
public TestDataVariationProvider(Type type, Func<object> testDataProvider)
{
this.Type = type;
this.TestDataProvider = testDataProvider;
}
public Func<object> TestDataProvider { get; private set; }
public Type Type { get; private set; }
}
}
/// <summary>
/// A generic base class for test data.
/// </summary>
/// <typeparam name="T">The type associated with the test data.</typeparam>
public abstract class TestData<T> : TestData, IEnumerable<T>
{
private static readonly Type OpenIEnumerableType = typeof(IEnumerable<>);
private static readonly Type OpenListType = typeof(List<>);
private static readonly Type OpenIQueryableType = typeof(IQueryable<>);
private static readonly Type OpenDictionaryType = typeof(Dictionary<,>);
private static readonly Type OpenTestDataHolderType = typeof(TestDataHolder<>);
private int dictionaryKey;
/// <summary>
/// Initializes a new instance of the <see cref="TestData&lt;T&gt;"/> class.
/// </summary>
protected TestData()
: base(typeof(T))
{
Type[] typeParams = new Type[] { this.Type };
Type[] dictionaryTypeParams = new Type[] { typeof(string), this.Type };
Type arrayType = this.Type.MakeArrayType();
Type listType = OpenListType.MakeGenericType(typeParams);
Type iEnumerableType = OpenIEnumerableType.MakeGenericType(typeParams);
Type iQueryableType = OpenIQueryableType.MakeGenericType(typeParams);
Type dictionaryType = OpenDictionaryType.MakeGenericType(dictionaryTypeParams);
Type testDataHolderType = OpenTestDataHolderType.MakeGenericType(typeParams);
this.RegisterTestDataVariation(TestDataVariations.AsInstance, this.Type, () => GetTypedTestData());
this.RegisterTestDataVariation(TestDataVariations.AsArray, arrayType, GetTestDataAsArray);
this.RegisterTestDataVariation(TestDataVariations.AsIEnumerable, iEnumerableType, GetTestDataAsIEnumerable);
this.RegisterTestDataVariation(TestDataVariations.AsIQueryable, iQueryableType, GetTestDataAsIQueryable);
this.RegisterTestDataVariation(TestDataVariations.AsList, listType, GetTestDataAsList);
this.RegisterTestDataVariation(TestDataVariations.AsDictionary, dictionaryType, GetTestDataAsDictionary);
this.RegisterTestDataVariation(TestDataVariations.AsClassMember, testDataHolderType, GetTestDataInHolder);
}
public IEnumerator<T> GetEnumerator()
{
return (IEnumerator<T>)this.GetTypedTestData().ToList().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)this.GetTypedTestData().ToList().GetEnumerator();
}
/// <summary>
/// Gets the test data as an array.
/// </summary>
/// <returns>An array of test data of the given type.</returns>
public T[] GetTestDataAsArray()
{
return this.GetTypedTestData().ToArray();
}
/// <summary>
/// Gets the test data as a <see cref="List<>"/>.
/// </summary>
/// <returns>A <see cref="List<>"/> of test data of the given type.</returns>
public List<T> GetTestDataAsList()
{
return this.GetTypedTestData().ToList();
}
/// <summary>
/// Gets the test data as an <see cref="IEnumerable<>"/>.
/// </summary>
/// <returns>An <see cref="IEnumerable<>"/> of test data of the given type.</returns>
public IEnumerable<T> GetTestDataAsIEnumerable()
{
return this.GetTypedTestData().AsEnumerable();
}
/// <summary>
/// Gets the test data as an <see cref="IQueryable<>"/>.
/// </summary>
/// <returns>An <see cref="IQueryable<>"/> of test data of the given type.</returns>
public IQueryable<T> GetTestDataAsIQueryable()
{
return this.GetTypedTestData().AsQueryable();
}
public Dictionary<string, T> GetTestDataAsDictionary()
{
// Some TestData collections contain duplicates e.g. UintTestData contains both 0 and UInt32.MinValue.
// Therefore use dictionaryKey, not _unused.ToString(). Reset key to keep dictionaries consistent if used
// multiple times.
dictionaryKey = 0;
return this.GetTypedTestData().ToDictionary(_unused => (dictionaryKey++).ToString());
}
public IEnumerable<TestDataHolder<T>> GetTestDataInHolder()
{
return this.GetTypedTestData().Select(value => new TestDataHolder<T> { V1 = value, });
}
/// <summary>
/// Must be implemented by derived types to return test data of the given type.
/// </summary>
/// <returns>Test data of the given type.</returns>
protected abstract IEnumerable<T> GetTypedTestData();
}
}

Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Globalization;
namespace Microsoft.TestCommon
{
/// <summary>
/// Equatable class wrapping a single instance of type <paramref name="T"/>. Equatable to ease test assertions.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> to wrap.</typeparam>
public class TestDataHolder<T> : IEquatable<TestDataHolder<T>>
{
public T V1 { get; set; }
bool IEquatable<TestDataHolder<T>>.Equals(TestDataHolder<T> other)
{
if (other == null)
{
return false;
}
return Object.Equals(V1, other.V1);
}
public override bool Equals(object obj)
{
TestDataHolder<T> that = obj as TestDataHolder<T>;
return ((IEquatable<TestDataHolder<T>>)this).Equals(that);
}
public override int GetHashCode()
{
if (typeof(ValueType).IsAssignableFrom(typeof(T)) || V1 != null)
{
return V1.GetHashCode();
}
else
{
return 0;
}
}
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{{ V1: '{0}' }}", V1);
}
}
}

Просмотреть файл

@ -0,0 +1,115 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
/// <summary>
/// An flags enum that can be used to indicate different variations of a given
/// <see cref="TestData"/> instance.
/// </summary>
[Flags]
public enum TestDataVariations
{
/// <summary>
/// An individual instance of a given <see cref="TestData"/> type.
/// </summary>
AsInstance = 0x1,
/// <summary>
/// An individual instance of a type that derives from a given <see cref="TestData"/> type.
/// </summary>
AsDerivedType = 0x2,
/// <summary>
/// An individual instance of a given <see cref="TestData"/> type that has a property value
/// that is a known type of the declared property type.
/// </summary>
AsKnownType = 0x4,
/// <summary>
/// A <see cref="Nullable<>"/> instance of a given <see cref="TestData"/> type. Only applies to
/// instances of <see cref="ValueTypeTestData"/>.
/// </summary>
AsNullable = 0x8,
/// <summary>
/// An instance of a <see cref="System.Collections.Generic.List<>"/> of a given <see cref="TestData"/> type.
/// </summary>
AsList = 0x10,
/// <summary>
/// An instance of a array of the <see cref="TestData"/> type.
/// </summary>
AsArray = 0x20,
/// <summary>
/// An instance of an <see cref="System.Collections.Generic.IEnumerable<>"/> of a given <see cref="TestData"/> type.
/// </summary>
AsIEnumerable = 0x40,
/// <summary>
/// An instance of an <see cref="System.Linq.IQueryable<>"/> of a given <see cref="TestData"/> type.
/// </summary>
AsIQueryable = 0x80,
/// <summary>
/// An instance of a DataContract type in which a given <see cref="TestData"/> type is a member.
/// </summary>
AsDataMember = 0x100,
/// <summary>
/// An instance of a type in which a given <see cref="TestData"/> type is decorated with a
/// <see cref="System.Xml.Serialization.XmlElementAttribute"/>.
/// </summary>
AsXmlElementProperty = 0x200,
/// <summary>
/// An instance of a <see cref="System.Collections.Generic.IDictionary{string,TValue}"/> of a given
/// <see cref="TestData"/> type.
/// </summary>
AsDictionary = 0x400,
/// <summary>
/// Add a <c>null</c> instance of the given <see cref="TestData"/> type to the data set. This variation is
/// not included in <see cref="All"/> or other variation masks.
/// </summary>
WithNull = 0x800,
/// <summary>
/// Individual instances of <see cref="TestDataHolder{T}"/> containing the given <see cref="TestData"/>. This
/// variation is not included in <see cref="All"/> or other variation masks.
/// </summary>
AsClassMember = 0x1000,
/// <summary>
/// All of the flags for single instance variations of a given <see cref="TestData"/> type.
/// </summary>
AllSingleInstances = AsInstance | AsDerivedType | AsKnownType | AsNullable,
/// <summary>
/// All of the flags for collection variations of a given <see cref="TestData"/> type.
/// </summary>
AllCollections = AsList | AsArray | AsIEnumerable | AsIQueryable | AsDictionary,
/// <summary>
/// All of the flags for variations in which a given <see cref="TestData"/> type is a property on another type.
/// </summary>
AllProperties = AsDataMember | AsXmlElementProperty,
/// <summary>
/// All of the flags for interface collection variations of a given <see cref="TestData"/> type.
/// </summary>
AllInterfaces = AsIEnumerable | AsIQueryable,
/// <summary>
/// All of the flags except for the interface collection variations of a given <see cref="TestData"/> type.
/// </summary>
AllNonInterfaces = All & ~AllInterfaces,
/// <summary>
/// All of the flags for all of the variations of a given <see cref="TestData"/> type.
/// </summary>
All = AllSingleInstances | AllCollections | AllProperties
}
}

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.TestCommon
{
public class ValueTypeTestData<T> : TestData<T> where T : struct
{
private static readonly Type OpenNullableType = typeof(Nullable<>);
private T[] testData;
public ValueTypeTestData(params T[] testData)
: base()
{
this.testData = testData;
Type[] typeParams = new Type[] { this.Type };
this.RegisterTestDataVariation(TestDataVariations.WithNull, OpenNullableType.MakeGenericType(typeParams), GetNullTestData);
this.RegisterTestDataVariation(TestDataVariations.AsNullable, OpenNullableType.MakeGenericType(typeParams), GetTestDataAsNullable);
}
public object GetNullTestData()
{
return null;
}
public IEnumerable<Nullable<T>> GetTestDataAsNullable()
{
return this.GetTypedTestData().Select(d => new Nullable<T>(d));
}
protected override IEnumerable<T> GetTypedTestData()
{
return this.testData;
}
}
}

Просмотреть файл

@ -0,0 +1,490 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
namespace Microsoft.TestCommon
{
/// <summary>
/// MSTest assertion class to provide convenience and assert methods for generic types
/// whose type parameters are not known at compile time.
/// </summary>
public class GenericTypeAssert
{
private static readonly GenericTypeAssert singleton = new GenericTypeAssert();
public static GenericTypeAssert Singleton { get { return singleton; } }
/// <summary>
/// Asserts the given <paramref name="genericBaseType"/> is a generic type and creates a new
/// bound generic type using <paramref name="genericParameterType"/>. It then asserts there
/// is a constructor that will accept <paramref name="parameterTypes"/> and returns it.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterType">The type of the single generic parameter to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <returns>The <see cref="ConstructorInfo"/> of that constructor which may be invoked to create that new generic type.</returns>
public ConstructorInfo GetConstructor(Type genericBaseType, Type genericParameterType, params Type[] parameterTypes)
{
Assert.NotNull(genericBaseType);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterType);
Assert.NotNull(parameterTypes);
Type genericType = genericBaseType.MakeGenericType(new Type[] { genericParameterType });
ConstructorInfo ctor = genericType.GetConstructor(parameterTypes);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<{1}>',", genericBaseType.Name, genericParameterType.Name));
return ctor;
}
/// <summary>
/// Asserts the given <paramref name="genericBaseType"/> is a generic type and creates a new
/// bound generic type using <paramref name="genericParameterType"/>. It then asserts there
/// is a constructor that will accept <paramref name="parameterTypes"/> and returns it.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterTypes">The types of the generic parameters to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <returns>The <see cref="ConstructorInfo"/> of that constructor which may be invoked to create that new generic type.</returns>
public ConstructorInfo GetConstructor(Type genericBaseType, Type[] genericParameterTypes, params Type[] parameterTypes)
{
Assert.NotNull(genericBaseType);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterTypes);
Assert.NotNull(parameterTypes);
Type genericType = genericBaseType.MakeGenericType(genericParameterTypes);
ConstructorInfo ctor = genericType.GetConstructor(parameterTypes);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<>',", genericBaseType.Name));
return ctor;
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterType">The type of the single generic parameter to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <param name="parameterValues">The list of values to supply to the constructor</param>
/// <returns>The instance created by calling that constructor.</returns>
public object InvokeConstructor(Type genericBaseType, Type genericParameterType, Type[] parameterTypes, object[] parameterValues)
{
ConstructorInfo ctor = GetConstructor(genericBaseType, genericParameterType, parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterTypse">The types of the generic parameters to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <param name="parameterValues">The list of values to supply to the constructor</param>
/// <returns>The instance created by calling that constructor.</returns>
public object InvokeConstructor(Type genericBaseType, Type[] genericParameterTypes, Type[] parameterTypes, object[] parameterValues)
{
ConstructorInfo ctor = GetConstructor(genericBaseType, genericParameterTypes, parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from the types of <paramref name="parameterValues"/>.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterType">The type of the single generic parameter to apply to create a bound generic type.</param>
/// <param name="parameterValues">The list of values to supply to the constructor. It must be possible to determine the</param>
/// <returns>The instance created by calling that constructor.</returns>
public object InvokeConstructor(Type genericBaseType, Type genericParameterType, params object[] parameterValues)
{
Assert.NotNull(genericBaseType);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterType);
Type genericType = genericBaseType.MakeGenericType(new Type[] { genericParameterType });
ConstructorInfo ctor = FindConstructor(genericType, parameterValues);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<{1}>',", genericBaseType.Name, genericParameterType.Name));
return ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from the types of <paramref name="parameterValues"/>.
/// </summary>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterTypes">The types of the generic parameters to apply to create a bound generic type.</param>
/// <param name="parameterValues">The list of values to supply to the constructor. It must be possible to determine the</param>
/// <returns>The instance created by calling that constructor.</returns>
public object InvokeConstructor(Type genericBaseType, Type[] genericParameterTypes, params object[] parameterValues)
{
Assert.NotNull(genericBaseType);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterTypes);
Type genericType = genericBaseType.MakeGenericType(genericParameterTypes);
ConstructorInfo ctor = FindConstructor(genericType, parameterValues);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<>',", genericBaseType.Name));
return ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <typeparam name="T">The type of object the constuctor is expected to yield.</typeparam>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterType">The type of the single generic parameter to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <param name="parameterValues">The list of values to supply to the constructor</param>
/// <returns>An instance of type <typeparamref name="T"/>.</returns>
public T InvokeConstructor<T>(Type genericBaseType, Type genericParameterType, Type[] parameterTypes, object[] parameterValues)
{
ConstructorInfo ctor = GetConstructor(genericBaseType, genericParameterType, parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return (T)ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <typeparam name="T">The type of object the constuctor is expected to yield.</typeparam>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterTypes">The types of the generic parameters to apply to create a bound generic type.</param>
/// <param name="parameterTypes">The list of parameter types for a constructor that must exist.</param>
/// <param name="parameterValues">The list of values to supply to the constructor</param>
/// <returns>An instance of type <typeparamref name="T"/>.</returns>
public T InvokeConstructor<T>(Type genericBaseType, Type[] genericParameterTypes, Type[] parameterTypes, object[] parameterValues)
{
ConstructorInfo ctor = GetConstructor(genericBaseType, genericParameterTypes, parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return (T)ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <typeparam name="T">The type of object the constuctor is expected to yield.</typeparam>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterType">The type of the single generic parameter to apply to create a bound generic type.</param>
/// <param name="parameterValues">The list of values to supply to the constructor. It must be possible to determine the</param>
/// <returns>The instance created by calling that constructor.</returns>
/// <returns>An instance of type <typeparamref name="T"/>.</returns>
public T InvokeConstructor<T>(Type genericBaseType, Type genericParameterType, params object[] parameterValues)
{
Assert.NotNull(genericBaseType == null);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterType);
Type genericType = genericBaseType.MakeGenericType(new Type[] { genericParameterType });
ConstructorInfo ctor = FindConstructor(genericType, parameterValues);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<{1}>',", genericBaseType.Name, genericParameterType.Name));
return (T)ctor.Invoke(parameterValues);
}
/// <summary>
/// Creates a new bound generic type and invokes the constructor matched from <see cref="parameterTypes"/>.
/// </summary>
/// <typeparam name="T">The type of object the constuctor is expected to yield.</typeparam>
/// <param name="genericBaseType">The unbound generic base type.</param>
/// <param name="genericParameterTypes">The types of the generic parameters to apply to create a bound generic type.</param>
/// <param name="parameterValues">The list of values to supply to the constructor. It must be possible to determine the</param>
/// <returns>The instance created by calling that constructor.</returns>
/// <returns>An instance of type <typeparamref name="T"/>.</returns>
public T InvokeConstructor<T>(Type genericBaseType, Type[] genericParameterTypes, params object[] parameterValues)
{
Assert.NotNull(genericBaseType);
Assert.True(genericBaseType.IsGenericTypeDefinition);
Assert.NotNull(genericParameterTypes);
Type genericType = genericBaseType.MakeGenericType(genericParameterTypes);
ConstructorInfo ctor = FindConstructor(genericType, parameterValues);
Assert.True(ctor != null, String.Format("Test error: failed to locate generic ctor for type '{0}<>',", genericBaseType.Name));
return (T)ctor.Invoke(parameterValues);
}
/// <summary>
/// Asserts the given instance is one from a generic type of the specified parameter type.
/// </summary>
/// <typeparam name="T">The type of instance.</typeparam>
/// <param name="instance">The instance to test.</param>
/// <param name="genericTypeParameter">The type of the generic parameter to which the instance's generic type should have been bound.</param>
public void IsCorrectGenericType<T>(T instance, Type genericTypeParameter)
{
Assert.NotNull(instance);
Assert.NotNull(genericTypeParameter);
Assert.True(instance.GetType().IsGenericType);
Type[] genericArguments = instance.GetType().GetGenericArguments();
Assert.Equal(1, genericArguments.Length);
Assert.Equal(genericTypeParameter, genericArguments[0]);
}
/// <summary>
/// Invokes via Reflection the method on the given instance.
/// </summary>
/// <param name="instance">The instance to use.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeMethod(object instance, string methodName, Type[] parameterTypes, object[] parameterValues)
{
Assert.NotNull(instance);
Assert.NotNull(parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
MethodInfo methodInfo = instance.GetType().GetMethod(methodName, parameterTypes);
Assert.NotNull(methodInfo);
return methodInfo.Invoke(instance, parameterValues);
}
/// <summary>
/// Invokes via Reflection the static method on the given type.
/// </summary>
/// <param name="type">The type containing the method.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeMethod(Type type, string methodName, Type[] parameterTypes, object[] parameterValues)
{
Assert.NotNull(type);
Assert.NotNull(parameterTypes);
Assert.NotNull(parameterValues);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
MethodInfo methodInfo = type.GetMethod(methodName, parameterTypes);
Assert.NotNull(methodInfo);
return methodInfo.Invoke(null, parameterValues);
}
/// <summary>
/// Invokes via Reflection the static method on the given type.
/// </summary>
/// <param name="type">The type containing the method.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The generic parameter type of the method.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public MethodInfo CreateGenericMethod(Type type, string methodName, Type genericParameterType, Type[] parameterTypes)
{
Assert.NotNull(type);
Assert.NotNull(parameterTypes);
Assert.NotNull(genericParameterType);
//MethodInfo methodInfo = type.GetMethod(methodName, parameterTypes);
MethodInfo methodInfo = type.GetMethods().Where((m) => m.Name.Equals(methodName, StringComparison.OrdinalIgnoreCase) && m.IsGenericMethod && AreAssignableFrom(m.GetParameters(), parameterTypes)).FirstOrDefault();
Assert.NotNull(methodInfo);
Assert.True(methodInfo.IsGenericMethod);
MethodInfo genericMethod = methodInfo.MakeGenericMethod(genericParameterType);
Assert.NotNull(genericMethod);
return genericMethod;
}
/// <summary>
/// Invokes via Reflection the static generic method on the given type.
/// </summary>
/// <param name="type">The type containing the method.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The generic parameter type of the method.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeGenericMethod(Type type, string methodName, Type genericParameterType, Type[] parameterTypes, object[] parameterValues)
{
MethodInfo methodInfo = CreateGenericMethod(type, methodName, genericParameterType, parameterTypes);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return methodInfo.Invoke(null, parameterValues);
}
/// <summary>
/// Invokes via Reflection the generic method on the given instance.
/// </summary>
/// <param name="instance">The instance on which to invoke the method.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The generic parameter type of the method.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeGenericMethod(object instance, string methodName, Type genericParameterType, Type[] parameterTypes, object[] parameterValues)
{
Assert.NotNull(instance);
MethodInfo methodInfo = CreateGenericMethod(instance.GetType(), methodName, genericParameterType, parameterTypes);
Assert.Equal(parameterTypes.Length, parameterValues.Length);
return methodInfo.Invoke(instance, parameterValues);
}
/// <summary>
/// Invokes via Reflection the generic method on the given instance.
/// </summary>
/// <typeparam name="T">The type of the return value from the method.</typeparam>
/// <param name="instance">The instance on which to invoke the method.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The generic parameter type of the method.</param>
/// <param name="parameterTypes">The types of the parameters to the method.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public T InvokeGenericMethod<T>(object instance, string methodName, Type genericParameterType, Type[] parameterTypes, object[] parameterValues)
{
return (T)InvokeGenericMethod(instance, methodName, genericParameterType, parameterTypes, parameterValues);
}
/// <summary>
/// Invokes via Reflection the method on the given instance.
/// </summary>
/// <param name="instance">The instance to use.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeMethod(object instance, string methodName, params object[] parameterValues)
{
Assert.NotNull(instance);
MethodInfo methodInfo = FindMethod(instance.GetType(), methodName, parameterValues);
Assert.NotNull(methodInfo);
return methodInfo.Invoke(instance, parameterValues);
}
/// <summary>
/// Invokes via Reflection the static method on the given type.
/// </summary>
/// <param name="instance">The instance to use.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeMethod(Type type, string methodName, params object[] parameterValues)
{
Assert.NotNull(type);
MethodInfo methodInfo = FindMethod(type, methodName, parameterValues);
Assert.NotNull(methodInfo);
return methodInfo.Invoke(null, parameterValues);
}
/// <summary>
/// Invokes via Reflection the method on the given instance.
/// </summary>
/// <param name="instance">The instance to use.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The type of the generic parameter.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeGenericMethod(object instance, string methodName, Type genericParameterType, params object[] parameterValues)
{
Assert.NotNull(instance);
Assert.NotNull(genericParameterType);
MethodInfo methodInfo = FindMethod(instance.GetType(), methodName, parameterValues);
Assert.NotNull(methodInfo);
Assert.True(methodInfo.IsGenericMethod);
MethodInfo genericMethod = methodInfo.MakeGenericMethod(genericParameterType);
return genericMethod.Invoke(instance, parameterValues);
}
/// <summary>
/// Invokes via Reflection the method on the given instance.
/// </summary>
/// <param name="instance">The instance to use.</param>
/// <param name="methodName">The name of the method to call.</param>
/// <param name="genericParameterType">The type of the generic parameter.</param>
/// <param name="parameterValues">The values to supply to the method.</param>
/// <returns>The results of the method.</returns>
public object InvokeGenericMethod(Type type, string methodName, Type genericParameterType, params object[] parameterValues)
{
Assert.NotNull(type);
Assert.NotNull(genericParameterType);
MethodInfo methodInfo = FindMethod(type, methodName, parameterValues);
Assert.NotNull(methodInfo);
Assert.True(methodInfo.IsGenericMethod);
MethodInfo genericMethod = methodInfo.MakeGenericMethod(genericParameterType);
return genericMethod.Invoke(null, parameterValues);
}
/// <summary>
/// Retrieves the value from the specified property.
/// </summary>
/// <param name="instance">The instance containing the property value.</param>
/// <param name="propertyName">The name of the property.</param>
/// <param name="failureMessage">The error message to prefix any test assertions.</param>
/// <returns>The value returned from the property.</returns>
public object GetProperty(object instance, string propertyName, string failureMessage)
{
PropertyInfo propertyInfo = instance.GetType().GetProperty(propertyName);
Assert.NotNull(propertyInfo);
return propertyInfo.GetValue(instance, null);
}
private static bool AreAssignableFrom(Type[] parameterTypes, params object[] parameterValues)
{
Assert.NotNull(parameterTypes);
Assert.NotNull(parameterValues);
if (parameterTypes.Length != parameterValues.Length)
{
return false;
}
for (int i = 0; i < parameterTypes.Length; ++i)
{
if (!parameterTypes[i].IsInstanceOfType(parameterValues[i]))
{
return false;
}
}
return true;
}
private static bool AreAssignableFrom(ParameterInfo[] parameterInfos, params Type[] parameterTypes)
{
Assert.NotNull(parameterInfos);
Assert.NotNull(parameterTypes);
Type[] parameterInfoTypes = parameterInfos.Select<ParameterInfo, Type>((info) => info.ParameterType).ToArray();
if (parameterInfoTypes.Length != parameterTypes.Length)
{
return false;
}
for (int i = 0; i < parameterInfoTypes.Length; ++i)
{
// Generic parameters are assumed to be assignable
if (parameterInfoTypes[i].IsGenericParameter)
{
continue;
}
if (!parameterInfoTypes[i].IsAssignableFrom(parameterTypes[i]))
{
return false;
}
}
return true;
}
private static bool AreAssignableFrom(ParameterInfo[] parameterInfos, params object[] parameterValues)
{
Assert.NotNull(parameterInfos);
Assert.NotNull(parameterValues);
Type[] parameterTypes = parameterInfos.Select<ParameterInfo, Type>((info) => info.ParameterType).ToArray();
return AreAssignableFrom(parameterTypes, parameterValues);
}
private static ConstructorInfo FindConstructor(Type type, params object[] parameterValues)
{
Assert.NotNull(type);
Assert.NotNull(parameterValues);
return type.GetConstructors().FirstOrDefault((c) => AreAssignableFrom(c.GetParameters(), parameterValues));
}
private static MethodInfo FindMethod(Type type, string methodName, params object[] parameterValues)
{
Assert.NotNull(type);
Assert.False(String.IsNullOrWhiteSpace(methodName));
Assert.NotNull(parameterValues);
return type.GetMethods().FirstOrDefault((m) => String.Equals(m.Name, methodName, StringComparison.Ordinal) && AreAssignableFrom(m.GetParameters(), parameterValues));
}
}
}

Просмотреть файл

@ -0,0 +1,256 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
namespace Microsoft.TestCommon
{
/// <summary>
/// Unit test utility for testing <see cref="HttpResponseMessage"/> instances.
/// </summary>
public class HttpAssert
{
private const string CommaSeperator = ", ";
private static readonly HttpAssert singleton = new HttpAssert();
public static HttpAssert Singleton { get { return singleton; } }
/// <summary>
/// Asserts that the expected <see cref="HttpRequestMessage"/> is equal to the actual <see cref="HttpRequestMessage"/>.
/// </summary>
/// <param name="expected">The expected <see cref="HttpRequestMessage"/>. Should not be <c>null</c>.</param>
/// <param name="actual">The actual <see cref="HttpRequestMessage"/>. Should not be <c>null</c>.</param>
public void Equal(HttpRequestMessage expected, HttpRequestMessage actual)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.Version, actual.Version);
Equal(expected.Headers, actual.Headers);
if (expected.Content == null)
{
Assert.Null(actual.Content);
}
else
{
string expectedContent = CleanContentString(expected.Content.ReadAsStringAsync().Result);
string actualContent = CleanContentString(actual.Content.ReadAsStringAsync().Result);
Assert.Equal(expectedContent, actualContent);
Equal(expected.Content.Headers, actual.Content.Headers);
}
}
/// <summary>
/// Asserts that the expected <see cref="HttpResponseMessage"/> is equal to the actual <see cref="HttpResponseMessage"/>.
/// </summary>
/// <param name="expected">The expected <see cref="HttpResponseMessage"/>. Should not be <c>null</c>.</param>
/// <param name="actual">The actual <see cref="HttpResponseMessage"/>. Should not be <c>null</c>.</param>
public void Equal(HttpResponseMessage expected, HttpResponseMessage actual)
{
Equal(expected, actual, null);
}
/// <summary>
/// Asserts that the expected <see cref="HttpResponseMessage"/> is equal to the actual <see cref="HttpResponseMessage"/>.
/// </summary>
/// <param name="expected">The expected <see cref="HttpResponseMessage"/>. Should not be <c>null</c>.</param>
/// <param name="actual">The actual <see cref="HttpResponseMessage"/>. Should not be <c>null</c>.</param>
/// <param name="verifyContentCallback">The callback to verify the Content string. If it is null, Assert.Equal will be used. </param>
public void Equal(HttpResponseMessage expected, HttpResponseMessage actual, Action<string, string> verifyContentStringCallback)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.StatusCode, actual.StatusCode);
Assert.Equal(expected.ReasonPhrase, actual.ReasonPhrase);
Assert.Equal(expected.Version, actual.Version);
Equal(expected.Headers, actual.Headers);
if (expected.Content == null)
{
Assert.Null(actual.Content);
}
else
{
string expectedContent = CleanContentString(expected.Content.ReadAsStringAsync().Result);
string actualContent = CleanContentString(actual.Content.ReadAsStringAsync().Result);
if (verifyContentStringCallback != null)
{
verifyContentStringCallback(expectedContent, actualContent);
}
else
{
Assert.Equal(expectedContent, actualContent);
}
Equal(expected.Content.Headers, actual.Content.Headers);
}
}
/// <summary>
/// Asserts that the expected <see cref="HttpHeaders"/> instance is equal to the actual <see cref="actualHeaders"/> instance.
/// </summary>
/// <param name="expectedHeaders">The expected <see cref="HttpHeaders"/> instance. Should not be <c>null</c>.</param>
/// <param name="actualHeaders">The actual <see cref="HttpHeaders"/> instance. Should not be <c>null</c>.</param>
public void Equal(HttpHeaders expectedHeaders, HttpHeaders actualHeaders)
{
Assert.NotNull(expectedHeaders);
Assert.NotNull(actualHeaders);
Assert.Equal(expectedHeaders.Count(), actualHeaders.Count());
foreach (KeyValuePair<string, IEnumerable<string>> expectedHeader in expectedHeaders)
{
KeyValuePair<string, IEnumerable<string>> actualHeader = actualHeaders.FirstOrDefault(h => h.Key == expectedHeader.Key);
Assert.NotNull(actualHeader);
if (expectedHeader.Key == "Date")
{
HandleDateHeader(expectedHeader.Value.ToArray(), actualHeader.Value.ToArray());
}
else
{
string expectedHeaderStr = string.Join(CommaSeperator, expectedHeader.Value);
string actualHeaderStr = string.Join(CommaSeperator, actualHeader.Value);
Assert.Equal(expectedHeaderStr, actualHeaderStr);
}
}
}
/// <summary>
/// Asserts the given <see cref="HttpHeaders"/> contain the given <paramref name="values"/>
/// for the given <paramref name="name"/>.
/// </summary>
/// <param name="headers">The <see cref="HttpHeaders"/> to examine. It cannot be <c>null</c>.</param>
/// <param name="name">The name of the header. It cannot be empty.</param>
/// <param name="values">The values that must all be present. It cannot be null.</param>
public void Contains(HttpHeaders headers, string name, params string[] values)
{
Assert.NotNull(headers);
Assert.False(String.IsNullOrWhiteSpace(name), "Test error: name cannot be empty.");
Assert.NotNull(values);
IEnumerable<string> headerValues = null;
bool foundIt = headers.TryGetValues(name, out headerValues);
Assert.True(foundIt);
foreach (string value in values)
{
Assert.Contains(value, headerValues);
}
}
public bool IsKnownUnserializableType(Type type, Func<Type, bool> isTypeUnserializableCallback)
{
if (isTypeUnserializableCallback != null && isTypeUnserializableCallback(type))
{
return true;
}
if (type.IsGenericType)
{
if (typeof(IEnumerable).IsAssignableFrom(type))
{
if (type.GetMethod("Add") == null)
{
return true;
}
}
// Generic type -- recursively analyze generic arguments
return IsKnownUnserializableType(type.GetGenericArguments()[0], isTypeUnserializableCallback);
}
if (type.HasElementType && IsKnownUnserializableType(type.GetElementType(), isTypeUnserializableCallback))
{
return true;
}
return false;
}
public bool IsKnownUnserializable(Type type, object obj, Func<Type, bool> isTypeUnserializableCallback)
{
if (IsKnownUnserializableType(type, isTypeUnserializableCallback))
{
return true;
}
return obj != null && IsKnownUnserializableType(obj.GetType(), isTypeUnserializableCallback);
}
public bool IsKnownUnserializable(Type type, object obj)
{
return IsKnownUnserializable(type, obj, null);
}
public bool CanRoundTrip(Type type)
{
if (typeof(DateTime).IsAssignableFrom(type))
{
return false;
}
if (typeof(DateTimeOffset).IsAssignableFrom(type))
{
return false;
}
if (type.IsGenericType)
{
foreach (Type genericParameterType in type.GetGenericArguments())
{
if (!CanRoundTrip(genericParameterType))
{
return false;
}
}
}
if (type.HasElementType)
{
return CanRoundTrip(type.GetElementType());
}
return true;
}
private static void HandleDateHeader(string[] expectedDateHeaderValues, string[] actualDateHeaderValues)
{
Assert.Equal(expectedDateHeaderValues.Length, actualDateHeaderValues.Length);
for (int i = 0; i < expectedDateHeaderValues.Length; i++)
{
DateTime expectedDateTime = DateTime.Parse(expectedDateHeaderValues[i]);
DateTime actualDateTime = DateTime.Parse(actualDateHeaderValues[i]);
Assert.Equal(expectedDateTime.Year, actualDateTime.Year);
Assert.Equal(expectedDateTime.Month, actualDateTime.Month);
Assert.Equal(expectedDateTime.Day, actualDateTime.Day);
int hourDifference = Math.Abs(actualDateTime.Hour - expectedDateTime.Hour);
Assert.True(hourDifference <= 1);
int minuteDifference = Math.Abs(actualDateTime.Minute - expectedDateTime.Minute);
Assert.True(minuteDifference <= 1);
}
}
private static string CleanContentString(string content)
{
Assert.Null(content);
string cleanedContent = null;
// remove any port numbers from Uri's
cleanedContent = Regex.Replace(content, ":\\d+", "");
return cleanedContent;
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Net.Http.Headers;
namespace Microsoft.TestCommon
{
public class MediaTypeAssert
{
private static readonly MediaTypeAssert singleton = new MediaTypeAssert();
public static MediaTypeAssert Singleton { get { return singleton; } }
public void AreEqual(MediaTypeHeaderValue expected, MediaTypeHeaderValue actual, string errorMessage)
{
if (expected != null || actual != null)
{
Assert.NotNull(expected);
Assert.Equal(0, new MediaTypeHeaderValueComparer().Compare(expected, actual));
}
}
public void AreEqual(MediaTypeHeaderValue expected, string actual, string errorMessage)
{
if (expected != null || !String.IsNullOrEmpty(actual))
{
MediaTypeHeaderValue actualMediaType = new MediaTypeHeaderValue(actual);
Assert.NotNull(expected);
Assert.Equal(0, new MediaTypeHeaderValueComparer().Compare(expected, actualMediaType));
}
}
public void AreEqual(string expected, string actual, string errorMessage)
{
if (!String.IsNullOrEmpty(expected) || !String.IsNullOrEmpty(actual))
{
Assert.NotNull(expected);
MediaTypeHeaderValue expectedMediaType = new MediaTypeHeaderValue(expected);
MediaTypeHeaderValue actualMediaType = new MediaTypeHeaderValue(actual);
Assert.Equal(0, new MediaTypeHeaderValueComparer().Compare(expectedMediaType, actualMediaType));
}
}
public void AreEqual(string expected, MediaTypeHeaderValue actual, string errorMessage)
{
if (!String.IsNullOrEmpty(expected) || actual != null)
{
Assert.NotNull(expected);
MediaTypeHeaderValue expectedMediaType = new MediaTypeHeaderValue(expected);
Assert.Equal(0, new MediaTypeHeaderValueComparer().Compare(expectedMediaType, actual));
}
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
namespace Microsoft.TestCommon
{
public class MediaTypeHeaderValueComparer : IComparer<MediaTypeHeaderValue>
{
private static readonly MediaTypeHeaderValueComparer mediaTypeComparer = new MediaTypeHeaderValueComparer();
public MediaTypeHeaderValueComparer()
{
}
public static MediaTypeHeaderValueComparer Comparer
{
get
{
return mediaTypeComparer;
}
}
public int Compare(MediaTypeHeaderValue mediaType1, MediaTypeHeaderValue mediaType2)
{
ParsedMediaTypeHeaderValue parsedMediaType1 = new ParsedMediaTypeHeaderValue(mediaType1);
ParsedMediaTypeHeaderValue parsedMediaType2 = new ParsedMediaTypeHeaderValue(mediaType2);
int returnValue = CompareBasedOnQualityFactor(parsedMediaType1, parsedMediaType2);
if (returnValue == 0)
{
if (!String.Equals(parsedMediaType1.Type, parsedMediaType2.Type, StringComparison.OrdinalIgnoreCase))
{
if (parsedMediaType1.IsAllMediaRange)
{
return 1;
}
else if (parsedMediaType2.IsAllMediaRange)
{
return -1;
}
}
else if (!String.Equals(parsedMediaType1.SubType, parsedMediaType2.SubType, StringComparison.OrdinalIgnoreCase))
{
if (parsedMediaType1.IsSubTypeMediaRange)
{
return 1;
}
else if (parsedMediaType2.IsSubTypeMediaRange)
{
return -1;
}
}
else
{
if (!parsedMediaType1.HasNonQualityFactorParameter)
{
if (parsedMediaType2.HasNonQualityFactorParameter)
{
return 1;
}
}
else if (!parsedMediaType2.HasNonQualityFactorParameter)
{
return -1;
}
}
}
return returnValue;
}
private static int CompareBasedOnQualityFactor(ParsedMediaTypeHeaderValue parsedMediaType1, ParsedMediaTypeHeaderValue parsedMediaType2)
{
double qualityDifference = parsedMediaType1.QualityFactor - parsedMediaType2.QualityFactor;
if (qualityDifference < 0)
{
return 1;
}
else if (qualityDifference > 0)
{
return -1;
}
return 0;
}
}
}

Просмотреть файл

@ -0,0 +1,111 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Net.Http.Headers;
namespace Microsoft.TestCommon
{
internal class ParsedMediaTypeHeaderValue
{
private const string MediaRangeAsterisk = "*";
private const char MediaTypeSubTypeDelimiter = '/';
private const string QualityFactorParameterName = "q";
private const double DefaultQualityFactor = 1.0;
private MediaTypeHeaderValue mediaType;
private string type;
private string subType;
private bool? hasNonQualityFactorParameter;
private double? qualityFactor;
public ParsedMediaTypeHeaderValue(MediaTypeHeaderValue mediaType)
{
this.mediaType = mediaType;
string[] splitMediaType = mediaType.MediaType.Split(MediaTypeSubTypeDelimiter);
this.type = splitMediaType[0];
this.subType = splitMediaType[1];
}
public string Type
{
get
{
return this.type;
}
}
public string SubType
{
get
{
return this.subType;
}
}
public bool IsAllMediaRange
{
get
{
return this.IsSubTypeMediaRange && String.Equals(MediaRangeAsterisk, this.Type, StringComparison.Ordinal);
}
}
public bool IsSubTypeMediaRange
{
get
{
return String.Equals(MediaRangeAsterisk, this.SubType, StringComparison.Ordinal);
}
}
public bool HasNonQualityFactorParameter
{
get
{
if (!this.hasNonQualityFactorParameter.HasValue)
{
this.hasNonQualityFactorParameter = false;
foreach (NameValueHeaderValue param in this.mediaType.Parameters)
{
if (!String.Equals(QualityFactorParameterName, param.Name, StringComparison.Ordinal))
{
this.hasNonQualityFactorParameter = true;
}
}
}
return this.hasNonQualityFactorParameter.Value;
}
}
public string CharSet
{
get
{
return this.mediaType.CharSet;
}
}
public double QualityFactor
{
get
{
if (!this.qualityFactor.HasValue)
{
MediaTypeWithQualityHeaderValue mediaTypeWithQuality = this.mediaType as MediaTypeWithQualityHeaderValue;
if (mediaTypeWithQuality != null)
{
this.qualityFactor = mediaTypeWithQuality.Quality;
}
if (!this.qualityFactor.HasValue)
{
this.qualityFactor = DefaultQualityFactor;
}
}
return this.qualityFactor.Value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Text.RegularExpressions;
namespace Microsoft.TestCommon
{
public class RegexReplacement
{
Regex regex;
string replacement;
public RegexReplacement(Regex regex, string replacement)
{
this.regex = regex;
this.replacement = replacement;
}
public RegexReplacement(string regex, string replacement)
{
this.regex = new Regex(regex);
this.replacement = replacement;
}
public Regex Regex
{
get
{
return this.regex;
}
}
public string Replacement
{
get
{
return this.replacement;
}
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.Win32;
namespace Microsoft.TestCommon
{
public static class RuntimeEnvironment
{
private const string NetFx40FullSubKey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full";
private const string Version = "Version";
static RuntimeEnvironment()
{
object runtimeVersion = Registry.LocalMachine.OpenSubKey(RuntimeEnvironment.NetFx40FullSubKey).GetValue(RuntimeEnvironment.Version);
string versionFor40String = runtimeVersion as string;
if (versionFor40String != null)
{
VersionFor40 = new Version(versionFor40String);
}
}
private static Version VersionFor40;
public static bool IsVersion45Installed
{
get
{
return VersionFor40.Major > 4 || (VersionFor40.Major == 4 && VersionFor40.Minor >= 5);
}
}
}
}

Просмотреть файл

@ -0,0 +1,152 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Xml.Serialization;
namespace Microsoft.TestCommon
{
/// <summary>
/// MSTest utility for testing code operating against a stream.
/// </summary>
public class SerializerAssert
{
private static SerializerAssert singleton = new SerializerAssert();
public static SerializerAssert Singleton { get { return singleton; } }
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="XmlSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <param name="type">The type to serialize. It cannot be <c>null</c>.</param>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public void UsingXmlSerializer(Type type, object objectInstance, Action<Stream> codeThatChecks)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (codeThatChecks == null)
{
throw new ArgumentNullException("codeThatChecks");
}
XmlSerializer serializer = new XmlSerializer(type);
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, objectInstance);
stream.Flush();
stream.Seek(0L, SeekOrigin.Begin);
codeThatChecks(stream);
}
}
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="XmlSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public void UsingXmlSerializer<T>(T objectInstance, Action<Stream> codeThatChecks)
{
UsingXmlSerializer(typeof(T), objectInstance, codeThatChecks);
}
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="DataContractSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <param name="type">The type to serialize. It cannot be <c>null</c>.</param>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public void UsingDataContractSerializer(Type type, object objectInstance, Action<Stream> codeThatChecks)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (codeThatChecks == null)
{
throw new ArgumentNullException("codeThatChecks");
}
DataContractSerializer serializer = new DataContractSerializer(type);
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, objectInstance);
stream.Flush();
stream.Seek(0L, SeekOrigin.Begin);
codeThatChecks(stream);
}
}
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="DataContractSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public void UsingDataContractSerializer<T>(T objectInstance, Action<Stream> codeThatChecks)
{
UsingDataContractSerializer(typeof(T), objectInstance, codeThatChecks);
}
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="DataContractJsonSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <param name="type">The type to serialize. It cannot be <c>null</c>.</param>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public static void UsingDataContractJsonSerializer(Type type, object objectInstance, Action<Stream> codeThatChecks)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (codeThatChecks == null)
{
throw new ArgumentNullException("codeThatChecks");
}
DataContractJsonSerializer serializer = new DataContractJsonSerializer(type);
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, objectInstance);
stream.Flush();
stream.Seek(0L, SeekOrigin.Begin);
codeThatChecks(stream);
}
}
/// <summary>
/// Creates a <see cref="Stream"/>, serializes <paramref name="objectInstance"/> to it using
/// <see cref="DataContractJsonSerializer"/>, rewinds the stream and calls <see cref="codeThatChecks"/>.
/// </summary>
/// <typeparam name="T">The type to serialize.</typeparam>
/// <param name="objectInstance">The value to serialize.</param>
/// <param name="codeThatChecks">Code to check the contents of the stream.</param>
public void UsingDataContractJsonSerializer<T>(T objectInstance, Action<Stream> codeThatChecks)
{
UsingDataContractJsonSerializer(typeof(T), objectInstance, codeThatChecks);
}
}
}

Просмотреть файл

@ -0,0 +1,96 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.IO;
namespace Microsoft.TestCommon
{
//// TODO RONCAIN using System.Runtime.Serialization.Json;
/// <summary>
/// MSTest utility for testing code operating against a stream.
/// </summary>
public class StreamAssert
{
private static StreamAssert singleton = new StreamAssert();
public static StreamAssert Singleton { get { return singleton; } }
/// <summary>
/// Creates a <see cref="MemoryStream"/>, invokes <paramref name="codeThatWrites"/> to write to it,
/// rewinds the stream to the beginning and invokes <paramref name="codeThatReads"/>.
/// </summary>
/// <param name="codeThatWrites">Code to write to the stream. It cannot be <c>null</c>.</param>
/// <param name="codeThatReads">Code that reads from the stream. It cannot be <c>null</c>.</param>
public void WriteAndRead(Action<MemoryStream> codeThatWrites, Action<Stream> codeThatReads)
{
if (codeThatWrites == null)
{
throw new ArgumentNullException("codeThatWrites");
}
if (codeThatReads == null)
{
throw new ArgumentNullException("codeThatReads");
}
using (MemoryStream stream = new MemoryStream())
{
codeThatWrites(stream);
stream.Flush();
stream.Seek(0L, SeekOrigin.Begin);
codeThatReads(stream);
}
}
/// <summary>
/// Creates a <see cref="Stream"/>, invokes <paramref name="codeThatWrites"/> to write to it,
/// rewinds the stream to the beginning and invokes <paramref name="codeThatReads"/> to obtain
/// the result to return from this method.
/// </summary>
/// <param name="codeThatWrites">Code to write to the stream. It cannot be <c>null</c>.</param>
/// <param name="codeThatReads">Code that reads from the stream and returns the result. It cannot be <c>null</c>.</param>
/// <returns>The value returned from <paramref name="codeThatReads"/>.</returns>
public static object WriteAndReadResult(Action<Stream> codeThatWrites, Func<Stream, object> codeThatReads)
{
if (codeThatWrites == null)
{
throw new ArgumentNullException("codeThatWrites");
}
if (codeThatReads == null)
{
throw new ArgumentNullException("codeThatReads");
}
object result = null;
using (MemoryStream stream = new MemoryStream())
{
codeThatWrites(stream);
stream.Flush();
stream.Seek(0L, SeekOrigin.Begin);
result = codeThatReads(stream);
}
return result;
}
/// <summary>
/// Creates a <see cref="Stream"/>, invokes <paramref name="codeThatWrites"/> to write to it,
/// rewinds the stream to the beginning and invokes <paramref name="codeThatReads"/> to obtain
/// the result to return from this method.
/// </summary>
/// <typeparam name="T">The type of the result expected.</typeparam>
/// <param name="codeThatWrites">Code to write to the stream. It cannot be <c>null</c>.</param>
/// <param name="codeThatReads">Code that reads from the stream and returns the result. It cannot be <c>null</c>.</param>
/// <returns>The value returned from <paramref name="codeThatReads"/>.</returns>
public T WriteAndReadResult<T>(Action<Stream> codeThatWrites, Func<Stream, object> codeThatReads)
{
return (T)WriteAndReadResult(codeThatWrites, codeThatReads);
}
}
}

Просмотреть файл

@ -0,0 +1,100 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace Microsoft.TestCommon
{
/// <summary>
/// MSTest assert class to make assertions about tests using <see cref="Task"/>.
/// </summary>
public class TaskAssert
{
private static int timeOutMs = System.Diagnostics.Debugger.IsAttached ? TimeoutConstant.DefaultTimeout : TimeoutConstant.DefaultTimeout * 10;
private static TaskAssert singleton = new TaskAssert();
public static TaskAssert Singleton { get { return singleton; } }
/// <summary>
/// Asserts the given task has been started. TAP guidelines are that all
/// <see cref="Task"/> objects returned from public API's have been started.
/// </summary>
/// <param name="task">The <see cref="Task"/> to test.</param>
public void IsStarted(Task task)
{
Assert.NotNull(task);
Assert.True(task.Status != TaskStatus.Created);
}
/// <summary>
/// Asserts the given task completes successfully. This method will block the
/// current thread waiting for the task, but will timeout if it does not complete.
/// </summary>
/// <param name="task">The <see cref="Task"/> to test.</param>
public void Succeeds(Task task)
{
IsStarted(task);
task.Wait(timeOutMs);
AggregateException aggregateException = task.Exception;
Exception innerException = aggregateException == null ? null : aggregateException.InnerException;
Assert.Null(innerException);
}
/// <summary>
/// Asserts the given task completes successfully and returns a result.
/// Use this overload for a generic <see cref="Task"/> whose generic parameter is not known at compile time.
/// This method will block the current thread waiting for the task, but will timeout if it does not complete.
/// </summary>
/// <param name="task">The <see cref="Task"/> to test.</param>
/// <returns>The result from that task.</returns>
public object SucceedsWithResult(Task task)
{
Succeeds(task);
Assert.True(task.GetType().IsGenericType);
Type[] genericArguments = task.GetType().GetGenericArguments();
Assert.Equal(1, genericArguments.Length);
PropertyInfo resultProperty = task.GetType().GetProperty("Result");
Assert.NotNull(resultProperty);
return resultProperty.GetValue(task, null);
}
/// <summary>
/// Asserts the given task completes successfully and returns a <typeparamref name="T"/> result.
/// This method will block the current thread waiting for the task, but will timeout if it does not complete.
/// </summary>
/// <typeparam name="T">The result of the <see cref="Task"/>.</typeparam>
/// <param name="task">The <see cref="Task"/> to test.</param>
/// <returns>The result from that task.</returns>
public T SucceedsWithResult<T>(Task<T> task)
{
Succeeds(task);
return task.Result;
}
/// <summary>
/// Asserts the given <see cref="Task"/> completes successfully and yields
/// the expected result.
/// </summary>
/// <param name="task">The <see cref="Task"/> to test.</param>
/// <param name="expectedObj">The expected result.</param>
public void ResultEquals(Task task, object expectedObj)
{
object actualObj = SucceedsWithResult(task);
Assert.Equal(expectedObj, actualObj);
}
/// <summary>
/// Asserts the given <see cref="Task"/> completes successfully and yields
/// the expected result.
/// </summary>
/// <typeparam name="T">The type the task will return.</typeparam>
/// <param name="task">The task to test.</param>
/// <param name="expectedObj">The expected result.</param>
public void ResultEquals<T>(Task<T> task, T expectedObj)
{
T actualObj = SucceedsWithResult<T>(task);
Assert.Equal(expectedObj, actualObj);
}
}
}

Просмотреть файл

@ -0,0 +1,203 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Microsoft.TestCommon
{
public class TestDataSetAttribute : DataAttribute
{
public Type DeclaringType { get; set; }
public string PropertyName { get; set; }
public TestDataVariations TestDataVariations { get; set; }
private IEnumerable<Tuple<Type, string>> ExtraDataSets { get; set; }
public TestDataSetAttribute(Type declaringType, string propertyName, TestDataVariations testDataVariations = TestCommon.TestDataVariations.All)
{
DeclaringType = declaringType;
PropertyName = propertyName;
TestDataVariations = testDataVariations;
ExtraDataSets = new List<Tuple<Type, string>>();
}
public TestDataSetAttribute(Type declaringType, string propertyName,
Type declaringType1, string propertyName1,
TestDataVariations testDataVariations = TestCommon.TestDataVariations.All)
: this(declaringType, propertyName, testDataVariations)
{
ExtraDataSets = new List<Tuple<Type, string>> { Tuple.Create(declaringType1, propertyName1) };
}
public TestDataSetAttribute(Type declaringType, string propertyName,
Type declaringType1, string propertyName1,
Type declaringType2, string propertyName2,
TestDataVariations testDataVariations = TestCommon.TestDataVariations.All)
: this(declaringType, propertyName, testDataVariations)
{
ExtraDataSets = new List<Tuple<Type, string>> { Tuple.Create(declaringType1, propertyName1), Tuple.Create(declaringType2, propertyName2) };
}
public TestDataSetAttribute(Type declaringType, string propertyName,
Type declaringType1, string propertyName1,
Type declaringType2, string propertyName2,
Type declaringType3, string propertyName3,
TestDataVariations testDataVariations = TestCommon.TestDataVariations.All)
: this(declaringType, propertyName, testDataVariations)
{
ExtraDataSets = new List<Tuple<Type, string>> { Tuple.Create(declaringType1, propertyName1), Tuple.Create(declaringType2, propertyName2), Tuple.Create(declaringType3, propertyName3) };
}
public TestDataSetAttribute(Type declaringType, string propertyName,
Type declaringType1, string propertyName1,
Type declaringType2, string propertyName2,
Type declaringType3, string propertyName3,
Type declaringType4, string propertyName4,
TestDataVariations testDataVariations = TestCommon.TestDataVariations.All)
: this(declaringType, propertyName, testDataVariations)
{
ExtraDataSets = new List<Tuple<Type, string>>
{
Tuple.Create(declaringType1, propertyName1), Tuple.Create(declaringType2, propertyName2),
Tuple.Create(declaringType3, propertyName3), Tuple.Create(declaringType4, propertyName4)
};
}
public override IEnumerable<object[]> GetData(MethodInfo methodUnderTest, Type[] parameterTypes)
{
IEnumerable<object[]> baseDataSet = GetBaseDataSet(DeclaringType, PropertyName, TestDataVariations);
IEnumerable<IEnumerable<object[]>> extraDataSets = GetExtraDataSets();
IEnumerable<IEnumerable<object[]>> finalDataSets = (new[] { baseDataSet }).Concat(extraDataSets);
var datasets = CrossProduct(finalDataSets);
return datasets;
}
private static IEnumerable<object[]> CrossProduct(IEnumerable<IEnumerable<object[]>> datasets)
{
if (datasets.Count() == 1)
{
foreach (var dataset in datasets.First())
{
yield return dataset;
}
}
else
{
IEnumerable<object[]> datasetLeft = datasets.First();
IEnumerable<object[]> datasetRight = CrossProduct(datasets.Skip(1));
foreach (var dataLeft in datasetLeft)
{
foreach (var dataRight in datasetRight)
{
yield return dataLeft.Concat(dataRight).ToArray();
}
}
}
}
// The base data set(first one) can either be a TestDataSet or a TestDataSetCollection
private static IEnumerable<object[]> GetBaseDataSet(Type declaringType, string propertyName, TestDataVariations variations)
{
return TryGetDataSetFromTestDataCollection(declaringType, propertyName, variations) ?? GetDataSet(declaringType, propertyName);
}
private IEnumerable<IEnumerable<object[]>> GetExtraDataSets()
{
foreach (var tuple in ExtraDataSets)
{
yield return GetDataSet(tuple.Item1, tuple.Item2);
}
}
private static object GetTestDataPropertyValue(Type declaringType, string propertyName)
{
PropertyInfo property = declaringType.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Public);
if (property == null)
{
throw new ArgumentException(String.Format("Could not find public static property {0} on {1}", propertyName, declaringType.FullName));
}
else
{
return property.GetValue(null, null);
}
}
private static IEnumerable<object[]> GetDataSet(Type declaringType, string propertyName)
{
object propertyValue = GetTestDataPropertyValue(declaringType, propertyName);
// box the dataset items if the property is not a RefTypeTestData
IEnumerable<object> value = (propertyValue as IEnumerable<object>) ?? (propertyValue as IEnumerable).Cast<object>();
if (value == null)
{
throw new InvalidOperationException(String.Format("{0}.{1} is either null or does not implement IEnumerable", declaringType.FullName, propertyName));
}
IEnumerable<object[]> dataset = value as IEnumerable<object[]>;
if (dataset != null)
{
return dataset;
}
else
{
return value.Select((data) => new object[] { data });
}
}
private static IEnumerable<object[]> TryGetDataSetFromTestDataCollection(Type declaringType, string propertyName, TestDataVariations variations)
{
object propertyValue = GetTestDataPropertyValue(declaringType, propertyName);
IEnumerable<TestData> testDataCollection = propertyValue as IEnumerable<TestData>;
return testDataCollection == null ? null : GetDataSetFromTestDataCollection(testDataCollection, variations);
}
private static IEnumerable<object[]> GetDataSetFromTestDataCollection(IEnumerable<TestData> testDataCollection, TestDataVariations variations)
{
foreach (TestData testdataInstance in testDataCollection)
{
foreach (TestDataVariations variation in testdataInstance.GetSupportedTestDataVariations())
{
if ((variation & variations) == variation)
{
Type variationType = testdataInstance.GetAsTypeOrNull(variation);
object testData = testdataInstance.GetAsTestDataOrNull(variation);
if (AsSingleInstances(variation))
{
foreach (object obj in (IEnumerable)testData)
{
yield return new object[] { variationType, obj };
}
}
else
{
yield return new object[] { variationType, testData };
}
}
}
}
}
private static bool AsSingleInstances(TestDataVariations variation)
{
return variation == TestDataVariations.AsInstance ||
variation == TestDataVariations.AsNullable ||
variation == TestDataVariations.AsDerivedType ||
variation == TestDataVariations.AsKnownType ||
variation == TestDataVariations.AsDataMember ||
variation == TestDataVariations.AsClassMember ||
variation == TestDataVariations.AsXmlElementProperty;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon
{
/// <summary>
/// MSTest timeout constants for use with the <see cref="Microsoft.VisualStudio.TestTools.UnitTesting.TimeoutAttribute"/>.
/// </summary>
public class TimeoutConstant
{
private const int seconds = 1000;
/// <summary>
/// The default timeout for test methods.
/// </summary>
public const int DefaultTimeout = 30 * seconds;
/// <summary>
/// An extended timeout for longer running test methods.
/// </summary>
public const int ExtendedTimeout = 240 * seconds;
}
}

Просмотреть файл

@ -0,0 +1,163 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
/// <summary>
/// MSTest utility for testing that a given type has the expected properties such as being public, sealed, etc.
/// </summary>
public class TypeAssert
{
/// <summary>
/// Specifies a set of type properties to test for using the <see cref="CheckProperty"/> method.
/// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a bitwise combination of its member values.
/// </summary>
[Flags]
public enum TypeProperties
{
/// <summary>
/// Indicates that the type must be abstract.
/// </summary>
IsAbstract = 0x1,
/// <summary>
/// Indicates that the type must be a class.
/// </summary>
IsClass = 0x2,
/// <summary>
/// Indicates that the type must be a COM object.
/// </summary>
IsComObject = 0x4,
/// <summary>
/// Indicates that the type must be disposable.
/// </summary>
IsDisposable = 0x8,
/// <summary>
/// Indicates that the type must be an enum.
/// </summary>
IsEnum = 0x10,
/// <summary>
/// Indicates that the type must be a generic type.
/// </summary>
IsGenericType = 0x20,
/// <summary>
/// Indicates that the type must be a generic type definition.
/// </summary>
IsGenericTypeDefinition = 0x40,
/// <summary>
/// Indicates that the type must be an interface.
/// </summary>
IsInterface = 0x80,
/// <summary>
/// Indicates that the type must be nested and declared private.
/// </summary>
IsNestedPrivate = 0x100,
/// <summary>
/// Indicates that the type must be nested and declared public.
/// </summary>
IsNestedPublic = 0x200,
/// <summary>
/// Indicates that the type must be public.
/// </summary>
IsPublic = 0x400,
/// <summary>
/// Indicates that the type must be sealed.
/// </summary>
IsSealed = 0x800,
/// <summary>
/// Indicates that the type must be visible outside the assembly.
/// </summary>
IsVisible = 0x1000,
/// <summary>
/// Indicates that the type must be static.
/// </summary>
IsStatic = TypeAssert.TypeProperties.IsAbstract | TypeAssert.TypeProperties.IsSealed,
/// <summary>
/// Indicates that the type must be a public, visible class.
/// </summary>
IsPublicVisibleClass = TypeAssert.TypeProperties.IsClass | TypeAssert.TypeProperties.IsPublic | TypeAssert.TypeProperties.IsVisible
}
private static void CheckProperty(Type type, bool expected, bool actual, string property)
{
Assert.NotNull(type);
Assert.True(expected == actual, String.Format("Type '{0}' should{1} be {2}.", type.FullName, expected ? "" : " NOT", property));
}
/// <summary>
/// Determines whether the specified type has a given set of properties such as being public, sealed, etc.
/// The method asserts if one or more of the properties are not satisfied.
/// </summary>
/// <typeparam name="T">The type to test for properties.</typeparam>
/// <param name="typeProperties">The set of type properties to test for.</param>
public void HasProperties<T>(TypeProperties typeProperties)
{
HasProperties(typeof(T), typeProperties);
}
/// <summary>
/// Determines whether the specified type has a given set of properties such as being public, sealed, etc.
/// The method asserts if one or more of the properties are not satisfied.
/// </summary>
/// <typeparam name="T">The type to test for properties.</typeparam>
/// <typeparam name="TIsAssignableFrom">Verify that the type to test is assignable from this type.</typeparam>
/// <param name="typeProperties">The set of type properties to test for.</param>
public void HasProperties<T, TIsAssignableFrom>(TypeProperties typeProperties)
{
HasProperties(typeof(T), typeProperties, typeof(TIsAssignableFrom));
}
/// <summary>
/// Determines whether the specified type has a given set of properties such as being public, sealed, etc.
/// The method asserts if one or more of the properties are not satisfied.
/// </summary>
/// <param name="type">The type to test for properties.</param>
/// <param name="typeProperties">The set of type properties to test for.</param>
public void HasProperties(Type type, TypeProperties typeProperties)
{
HasProperties(type, typeProperties, null);
}
/// <summary>
/// Determines whether the specified type has a given set of properties such as being public, sealed, etc.
/// The method asserts if one or more of the properties are not satisfied.
/// </summary>
/// <param name="type">The type to test for properties.</param>
/// <param name="typeProperties">The set of type properties to test for.</param>
/// <param name="isAssignableFrom">Verify that the type to test is assignable from this type.</param>
public void HasProperties(Type type, TypeProperties typeProperties, Type isAssignableFrom)
{
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsAbstract) > 0, type.IsAbstract, "abstract");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsClass) > 0, type.IsClass, "a class");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsComObject) > 0, type.IsCOMObject, "a COM object");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsDisposable) > 0, typeof(IDisposable).IsAssignableFrom(type), "disposable");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsEnum) > 0, type.IsEnum, "an enum");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsGenericType) > 0, type.IsGenericType, "a generic type");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsGenericTypeDefinition) > 0, type.IsGenericTypeDefinition, "a generic type definition");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsInterface) > 0, type.IsInterface, "an interface");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsNestedPrivate) > 0, type.IsNestedPrivate, "nested private");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsNestedPublic) > 0, type.IsNestedPublic, "nested public");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsPublic) > 0, type.IsPublic, "public");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsSealed) > 0, type.IsSealed, "sealed");
TypeAssert.CheckProperty(type, (typeProperties & TypeProperties.IsVisible) > 0, type.IsVisible, "visible");
if (isAssignableFrom != null)
{
TypeAssert.CheckProperty(type, true, isAssignableFrom.IsAssignableFrom(type), String.Format("assignable from {0}", isAssignableFrom.FullName));
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum ByteEnum : byte
{
FirstByte,
SecondByte,
ThirdByte
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon.Types
{
[Flags]
public enum FlagsEnum
{
One = 0x1,
Two = 0x2,
Four = 0x4
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
/// <summary>
/// Tagging interface to assist comparing instances of these types.
/// </summary>
public interface INameAndIdContainer
{
string Name { get; set; }
int Id { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Microsoft.TestCommon.Types
{
[Serializable]
public class ISerializableType : ISerializable, INameAndIdContainer
{
private int id;
private string name;
public ISerializableType()
{
}
public ISerializableType(int id, string name)
{
this.id = id;
this.name = name;
}
public ISerializableType(SerializationInfo information, StreamingContext context)
{
this.id = information.GetInt32("Id");
this.name = information.GetString("Name");
}
public int Id
{
get
{
return this.id;
}
set
{
this.IdSet = true;
this.id = value;
}
}
public string Name
{
get
{
return this.name;
}
set
{
this.NameSet = true;
this.name = value;
}
}
public bool IdSet { get; private set; }
public bool NameSet { get; private set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Id", this.Id);
info.AddValue("Name", this.Name);
}
public static IEnumerable<ISerializableType> GetTestData()
{
return new ISerializableType[] { new ISerializableType(), new ISerializableType(1, "SomeName") };
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum LongEnum : long
{
FirstLong,
SecondLong,
ThirdLong,
FourthLong
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum SByteEnum : sbyte
{
FirstSByte,
SecondSByte,
ThirdSByte
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum ShortEnum : short
{
FirstShort,
SecondShort,
ThirdShort
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum SimpleEnum
{
First,
Second,
Third,
Fourth
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum UIntEnum : uint
{
FirstUInt,
SecondUInt,
ThirdUInt
}
}

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace Microsoft.TestCommon.Types
{
public enum UShortEnum : ushort
{
FirstUShort,
SecondUShort,
ThirdUShort
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;
namespace Microsoft.TestCommon
{
/// <summary>
/// Assert class that compares two XML strings for equality. Namespaces are ignored during comparison
/// </summary>
public class XmlAssert
{
public void Equal(string expected, string actual, params RegexReplacement[] regexReplacements)
{
if (regexReplacements != null)
{
for (int i = 0; i < regexReplacements.Length; i++)
{
actual = regexReplacements[i].Regex.Replace(actual, regexReplacements[i].Replacement);
}
}
Equal(XElement.Parse(expected), XElement.Parse(actual));
}
public void Equal(XElement expected, XElement actual)
{
Assert.Equal(Normalize(expected).ToString(), Normalize(actual).ToString());
}
private static XElement Normalize(XElement element)
{
if (element.HasElements)
{
return new XElement(
Encode(element.Name),
Normalize(element.Attributes()),
Normalize(element.Elements()));
}
if (element.IsEmpty)
{
return new XElement(
Encode(element.Name),
Normalize(element.Attributes()));
}
else
{
return new XElement(
Encode(element.Name),
Normalize(element.Attributes()),
element.Value);
}
}
private static IEnumerable<XAttribute> Normalize(IEnumerable<XAttribute> attributes)
{
return attributes
.Where((attrib) => !attrib.IsNamespaceDeclaration)
.Select((attrib) => new XAttribute(Encode(attrib.Name), attrib.Value))
.OrderBy(a => a.Name.ToString());
}
private static IEnumerable<XElement> Normalize(IEnumerable<XElement> elements)
{
return elements
.Select(e => Normalize(e))
.OrderBy(a => a.ToString());
}
private static string Encode(XName name)
{
return string.Format("{0}_{1}", HttpUtility.UrlEncode(name.NamespaceName).Replace('%', '_'), name.LocalName);
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
/// <summary>
/// An enumeration of known platforms that the unit test might be running under.
/// </summary>
[Flags]
public enum Platform
{
/// <summary>
/// A special value used to indicate that the test is valid on all known platforms.
/// </summary>
All = 0xFFFFFF,
/// <summary>
/// Indicates that the test wants to run on .NET 4 (when used with
/// <see cref="FactAttribute.Platforms"/> and/or <see cref="TheoryAttribute.Platforms"/>),
/// or that the current platform that the test is running on is .NET 4 (when used with the
/// <see cref="PlatformInfo.Platform"/>, <see cref="FactAttribute.Platform"/>, and/or
/// <see cref="TheoryAttribute.Platform"/>).
/// </summary>
Net40 = 0x01,
/// <summary>
/// Indicates that the test wants to run on .NET 4.5 (when used with
/// <see cref="FactAttribute.Platforms"/> and/or <see cref="TheoryAttribute.Platforms"/>),
/// or that the current platform that the test is running on is .NET 4.5 (when used with the
/// <see cref="PlatformInfo.Platform"/>, <see cref="FactAttribute.Platform"/>, and/or
/// <see cref="TheoryAttribute.Platform"/>).
/// </summary>
Net45 = 0x02,
}
}

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
/// <summary>
/// Used to retrieve the currently running platform.
/// </summary>
public static class PlatformInfo
{
private const string _net45TypeName = "System.IWellKnownStringEqualityComparer, mscorlib, Version=4.0.0.0, PublicKeyToken=b77a5c561934e089";
private static Lazy<Platform> _platform = new Lazy<Platform>(GetPlatform, isThreadSafe: true);
/// <summary>
/// Gets the platform that the unit test is currently running on.
/// </summary>
public static Platform Platform
{
get { return _platform.Value; }
}
private static Platform GetPlatform()
{
if (Type.GetType(_net45TypeName, throwOnError: false) != null)
{
return Platform.Net45;
}
return Platform.Net40;
}
}
}

Просмотреть файл

@ -0,0 +1,135 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
namespace Microsoft.TestCommon
{
/// <summary>
/// This class allocates ports while ensuring that:
/// 1. Ports that are permanentaly taken (or taken for the duration of the test) are not being attempted to be used.
/// 2. Ports are not shared across different tests (but you can allocate two different ports in the same test).
///
/// Gotcha: If another application grabs a port during the test, we have a race condition.
/// </summary>
[DebuggerDisplay("Port: {PortNumber}, Port count for this app domain: {_appDomainOwnedPorts.Count}")]
public class PortReserver : IDisposable
{
private Mutex _portMutex;
// We use this list to hold on to all the ports used because the Mutex will be blown through on the same thread.
// Theoretically we can do a thread local hashset, but that makes dispose thread dependant, or requires more complicated concurrency checks.
// Since practically there is no perf issue or concern here, this keeps the code the simplest possible.
private static HashSet<int> _appDomainOwnedPorts = new HashSet<int>();
public int PortNumber
{
get;
private set;
}
public PortReserver(int basePort = 50231)
{
if (basePort <= 0)
{
throw new InvalidOperationException();
}
// Grab a cross appdomain/cross process/cross thread lock, to ensure only one port is reserved at a time.
using (Mutex mutex = GetGlobalMutex())
{
try
{
int port = basePort - 1;
while (true)
{
port++;
if (port > 65535)
{
throw new InvalidOperationException("Exceeded port range");
}
// AppDomainOwnedPorts check enables reserving two ports from the same thread in sequence.
// ListUsedTCPPort prevents port contention with other apps.
if (_appDomainOwnedPorts.Contains(port) ||
ListUsedTCPPort().Any(endPoint => endPoint.Port == port))
{
continue;
}
string mutexName = "WebStack-Port-" + port.ToString(CultureInfo.InvariantCulture); // Create a well known mutex
_portMutex = new Mutex(initiallyOwned: false, name: mutexName);
// If no one else is using this port grab it.
if (_portMutex.WaitOne(millisecondsTimeout: 0))
{
break;
}
// dispose this mutex since the port it represents is not available.
_portMutex.Dispose();
_portMutex = null;
}
PortNumber = port;
_appDomainOwnedPorts.Add(port);
}
finally
{
mutex.ReleaseMutex();
}
}
}
public string BaseUri
{
get
{
return String.Format(CultureInfo.InvariantCulture, "http://localhost:{0}/", PortNumber);
}
}
public void Dispose()
{
if (PortNumber == -1)
{
// Object already disposed
return;
}
using (Mutex mutex = GetGlobalMutex())
{
_portMutex.Dispose();
_appDomainOwnedPorts.Remove(PortNumber);
PortNumber = -1;
}
}
private static Mutex GetGlobalMutex()
{
Mutex mutex = new Mutex(initiallyOwned: false, name: "WebStack-RandomPortAcquisition");
if (!mutex.WaitOne(30000))
{
throw new InvalidOperationException();
}
return mutex;
}
private static IPEndPoint[] ListUsedTCPPort()
{
var usedPort = new HashSet<int>();
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
return ipGlobalProperties.GetActiveTcpListeners();
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel;
using System.Reflection;
using Microsoft.TestCommon;
namespace System.Web.WebPages.TestUtils
{
public static class PreAppStartTestHelper
{
public static void TestPreAppStartClass(Type preAppStartType)
{
string typeMessage = String.Format("The type '{0}' must be static, public, and named 'PreApplicationStartCode'.", preAppStartType.FullName);
Assert.True(preAppStartType.IsSealed && preAppStartType.IsAbstract && preAppStartType.IsPublic && preAppStartType.Name == "PreApplicationStartCode", typeMessage);
string editorBrowsableMessage = String.Format("The only attribute on type '{0}' must be [EditorBrowsable(EditorBrowsableState.Never)].", preAppStartType.FullName);
object[] attrs = preAppStartType.GetCustomAttributes(typeof(EditorBrowsableAttribute), true);
Assert.True(attrs.Length == 1 && ((EditorBrowsableAttribute)attrs[0]).State == EditorBrowsableState.Never, editorBrowsableMessage);
string startMethodMessage = String.Format("The only public member on type '{0}' must be a method called Start().", preAppStartType.FullName);
MemberInfo[] publicMembers = preAppStartType.GetMembers(BindingFlags.Public | BindingFlags.Static);
Assert.True(publicMembers.Length == 1, startMethodMessage);
Assert.True(publicMembers[0].MemberType == MemberTypes.Method, startMethodMessage);
Assert.True(publicMembers[0].Name == "Start", startMethodMessage);
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Threading;
namespace Microsoft.TestCommon
{
/// <summary>
/// Preserves the current <see cref="SynchronizationContext"/>. Use this attribute on
/// tests which modify the current <see cref="SynchronizationContext"/>.
/// </summary>
public class PreserveSyncContextAttribute : Xunit.BeforeAfterTestAttribute
{
private SynchronizationContext _syncContext;
public override void Before(System.Reflection.MethodInfo methodUnderTest)
{
_syncContext = SynchronizationContext.Current;
}
public override void After(System.Reflection.MethodInfo methodUnderTest)
{
SynchronizationContext.SetSynchronizationContext(_syncContext);
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class PropertyDataAttribute : Xunit.Extensions.PropertyDataAttribute
{
public PropertyDataAttribute(string propertyName)
: base(propertyName)
{
}
}
}

Просмотреть файл

@ -0,0 +1,221 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Microsoft.TestCommon
{
public class ReflectionAssert
{
private static PropertyInfo GetPropertyInfo<T, TProp>(Expression<Func<T, TProp>> property)
{
if (property.Body is MemberExpression)
{
return (PropertyInfo)((MemberExpression)property.Body).Member;
}
else if (property.Body is UnaryExpression && property.Body.NodeType == ExpressionType.Convert)
{
return (PropertyInfo)((MemberExpression)((UnaryExpression)property.Body).Operand).Member;
}
else
{
throw new InvalidOperationException("Could not determine property from lambda expression.");
}
}
private static void TestPropertyValue<TInstance, TValue>(TInstance instance, Func<TInstance, TValue> getFunc, Action<TInstance, TValue> setFunc, TValue valueToSet, TValue valueToCheck)
{
setFunc(instance, valueToSet);
TValue newValue = getFunc(instance);
Assert.Equal(valueToCheck, newValue);
}
private static void TestPropertyValue<TInstance, TValue>(TInstance instance, Func<TInstance, TValue> getFunc, Action<TInstance, TValue> setFunc, TValue value)
{
TestPropertyValue(instance, getFunc, setFunc, value, value);
}
public void Property<T, TResult>(T instance, Expression<Func<T, TResult>> propertyGetter, TResult expectedDefaultValue, bool allowNull = false, TResult roundTripTestValue = null) where TResult : class
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, TResult> getFunc = (obj) => (TResult)property.GetValue(obj, index: null);
Action<T, TResult> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
if (allowNull)
{
TestPropertyValue(instance, getFunc, setFunc, null);
}
else
{
Assert.ThrowsArgumentNull(() =>
{
setFunc(instance, null);
}, "value");
}
if (roundTripTestValue != null)
{
TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue);
}
}
public void IntegerProperty<T, TResult>(T instance, Expression<Func<T, TResult>> propertyGetter, TResult expectedDefaultValue,
TResult? minLegalValue, TResult? illegalLowerValue,
TResult? maxLegalValue, TResult? illegalUpperValue,
TResult roundTripTestValue) where TResult : struct
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, TResult> getFunc = (obj) => (TResult)property.GetValue(obj, index: null);
Action<T, TResult> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
if (minLegalValue.HasValue)
{
TestPropertyValue(instance, getFunc, setFunc, minLegalValue.Value);
}
if (maxLegalValue.HasValue)
{
TestPropertyValue(instance, getFunc, setFunc, maxLegalValue.Value);
}
if (illegalLowerValue.HasValue)
{
Assert.ThrowsArgumentGreaterThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", minLegalValue.Value.ToString(), illegalLowerValue.Value);
}
if (illegalUpperValue.HasValue)
{
Assert.ThrowsArgumentLessThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", maxLegalValue.Value.ToString(), illegalUpperValue.Value);
}
TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue);
}
public void NullableIntegerProperty<T, TResult>(T instance, Expression<Func<T, TResult?>> propertyGetter, TResult? expectedDefaultValue,
TResult? minLegalValue, TResult? illegalLowerValue,
TResult? maxLegalValue, TResult? illegalUpperValue,
TResult roundTripTestValue) where TResult : struct
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, TResult?> getFunc = (obj) => (TResult?)property.GetValue(obj, index: null);
Action<T, TResult?> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
TestPropertyValue(instance, getFunc, setFunc, null);
if (minLegalValue.HasValue)
{
TestPropertyValue(instance, getFunc, setFunc, minLegalValue.Value);
}
if (maxLegalValue.HasValue)
{
TestPropertyValue(instance, getFunc, setFunc, maxLegalValue.Value);
}
if (illegalLowerValue.HasValue)
{
Assert.ThrowsArgumentGreaterThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", minLegalValue.Value.ToString(), illegalLowerValue.Value);
}
if (illegalUpperValue.HasValue)
{
Assert.ThrowsArgumentLessThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", maxLegalValue.Value.ToString(), illegalUpperValue.Value);
}
TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue);
}
public void BooleanProperty<T>(T instance, Expression<Func<T, bool>> propertyGetter, bool expectedDefaultValue)
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, bool> getFunc = (obj) => (bool)property.GetValue(obj, index: null);
Action<T, bool> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
TestPropertyValue(instance, getFunc, setFunc, !expectedDefaultValue);
}
public void EnumProperty<T, TResult>(T instance, Expression<Func<T, TResult>> propertyGetter, TResult expectedDefaultValue, TResult illegalValue, TResult roundTripTestValue) where TResult : struct
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, TResult> getFunc = (obj) => (TResult)property.GetValue(obj, index: null);
Action<T, TResult> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
Assert.ThrowsInvalidEnumArgument(() => { setFunc(instance, illegalValue); }, "value", Convert.ToInt32(illegalValue), typeof(TResult));
TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue);
}
public void EnumPropertyWithoutIllegalValueCheck<T, TResult>(T instance, Expression<Func<T, TResult>> propertyGetter, TResult expectedDefaultValue, TResult roundTripTestValue) where TResult : struct
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, TResult> getFunc = (obj) => (TResult)property.GetValue(obj, index: null);
Action<T, TResult> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue);
}
public void StringProperty<T>(T instance, Expression<Func<T, string>> propertyGetter, string expectedDefaultValue,
bool allowNullAndEmpty = true, bool treatNullAsEmpty = true)
{
PropertyInfo property = GetPropertyInfo(propertyGetter);
Func<T, string> getFunc = (obj) => (string)property.GetValue(obj, index: null);
Action<T, string> setFunc = (obj, value) => property.SetValue(obj, value, index: null);
Assert.Equal(expectedDefaultValue, getFunc(instance));
if (allowNullAndEmpty)
{
// Assert get/set works for null
TestPropertyValue(instance, getFunc, setFunc, null, treatNullAsEmpty ? String.Empty : null);
// Assert get/set works for String.Empty
TestPropertyValue(instance, getFunc, setFunc, String.Empty, String.Empty);
}
else
{
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
TestPropertyValue(instance, getFunc, setFunc, null);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
"value");
Assert.ThrowsArgumentNullOrEmpty(
delegate()
{
try
{
TestPropertyValue(instance, getFunc, setFunc, String.Empty);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
},
"value");
}
// Assert get/set works for arbitrary value
TestPropertyValue(instance, getFunc, setFunc, "TestValue");
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.Reflection;
using System.Threading;
namespace Microsoft.TestCommon
{
/// <summary>
/// Replaces the current culture and UI culture for the test.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class ReplaceCultureAttribute : Xunit.BeforeAfterTestAttribute
{
private CultureInfo _originalCulture;
private CultureInfo _originalUICulture;
public ReplaceCultureAttribute()
{
Culture = CultureReplacer.DefaultCultureName;
UICulture = CultureReplacer.DefaultUICultureName;
}
/// <summary>
/// Sets <see cref="Thread.CurrentCulture"/> for the test. Defaults to en-GB.
/// </summary>
/// <remarks>
/// en-GB is used here as the default because en-US is equivalent to the InvariantCulture. We
/// want to be able to find bugs where we're accidentally relying on the Invariant instead of the
/// user's culture.
/// </remarks>
public string Culture { get; set; }
/// <summary>
/// Sets <see cref="Thread.CurrentUICulture"/> for the test. Defaults to en-US.
/// </summary>
public string UICulture { get; set; }
public override void Before(MethodInfo methodUnderTest)
{
_originalCulture = Thread.CurrentThread.CurrentCulture;
_originalUICulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(Culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(UICulture);
}
public override void After(MethodInfo methodUnderTest)
{
Thread.CurrentThread.CurrentCulture = _originalCulture;
Thread.CurrentThread.CurrentUICulture = _originalUICulture;
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Security.Principal;
using System.Threading;
namespace Microsoft.TestCommon
{
public class RestoreThreadPrincipalAttribute : Xunit.BeforeAfterTestAttribute
{
private IPrincipal _originalPrincipal;
public override void Before(MethodInfo methodUnderTest)
{
_originalPrincipal = Thread.CurrentPrincipal;
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.NoPrincipal);
Thread.CurrentPrincipal = null;
}
public override void After(MethodInfo methodUnderTest)
{
Thread.CurrentPrincipal = _originalPrincipal;
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.UnauthenticatedPrincipal);
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Xunit.Sdk;
namespace Microsoft.TestCommon
{
// An early copy of the new string assert exception from xUnit.net 2.0 (temporarily, until it RTMs)
[Serializable]
internal class StringEqualException : AssertException
{
private static Dictionary<char, string> _encodings = new Dictionary<char, string> { { '\r', "\\r" }, { '\n', "\\n" }, { '\t', "\\t" }, { '\0', "\\0" } };
private string _message;
public StringEqualException(string expected, string actual, int expectedIndex, int actualIndex)
: base("Assert.Equal() failure")
{
Actual = actual;
ActualIndex = actualIndex;
Expected = expected;
ExpectedIndex = expectedIndex;
}
public string Actual { get; private set; }
public int ActualIndex { get; private set; }
public string Expected { get; private set; }
public int ExpectedIndex { get; private set; }
public override string Message
{
get
{
if (_message == null)
_message = CreateMessage();
return _message;
}
}
private string CreateMessage()
{
Tuple<string, string> printedExpected = ShortenAndEncode(Expected, ExpectedIndex, '↓');
Tuple<string, string> printedActual = ShortenAndEncode(Actual, ActualIndex, '↑');
return String.Format(
CultureInfo.CurrentCulture,
"{1}{0} {2}{0}Expected: {3}{0}Actual: {4}{0} {5}",
Environment.NewLine,
base.Message,
printedExpected.Item2,
printedExpected.Item1,
printedActual.Item1,
printedActual.Item2
);
}
private Tuple<string, string> ShortenAndEncode(string value, int position, char pointer)
{
int start = Math.Max(position - 20, 0);
int end = Math.Min(position + 41, value.Length);
StringBuilder printedValue = new StringBuilder(100);
StringBuilder printedPointer = new StringBuilder(100);
if (start > 0)
{
printedValue.Append("···");
printedPointer.Append(" ");
}
for (int idx = start; idx < end; ++idx)
{
char c = value[idx];
string encoding;
int paddingLength = 1;
if (_encodings.TryGetValue(c, out encoding))
{
printedValue.Append(encoding);
paddingLength = encoding.Length;
}
else
{
printedValue.Append(c);
}
if (idx < position)
{
printedPointer.Append(' ', paddingLength);
}
else if (idx == position)
{
printedPointer.AppendFormat("{0} (pos {1})", pointer, position);
}
}
if (end < value.Length)
{
printedValue.Append("···");
}
return new Tuple<string, string>(printedValue.ToString(), printedPointer.ToString());
}
protected override bool ExcludeStackFrame(string stackFrame)
{
return base.ExcludeStackFrame(stackFrame)
|| stackFrame.StartsWith("at Microsoft.TestCommon.Assert.", StringComparison.OrdinalIgnoreCase);
}
}
}

Просмотреть файл

@ -0,0 +1,135 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.TestCommon
{
// An early copy of the new string assert from xUnit.net 2.0 (temporarily, until it RTMs)
public partial class Assert
{
private const string NullDisplayValue = "(null)";
/// <summary>
/// Verifies that two strings are equivalent.
/// </summary>
/// <param name="expected">The expected string value.</param>
/// <param name="actual">The actual string value.</param>
/// <param name="ignoreCase">If set to <c>true</c>, ignores cases differences. The invariant culture is used.</param>
/// <param name="ignoreLineEndingDifferences">If set to <c>true</c>, treats \r\n, \r, and \n as equivalent.</param>
/// <param name="ignoreWhiteSpaceDifferences">If set to <c>true</c>, treats spaces and tabs (in any non-zero quantity) as equivalent.</param>
/// <exception cref="Microsoft.TestCommon.Assert.StringEqualException">Thrown when the strings are not equivalent.</exception>
public static void Equal(string expected, string actual, bool ignoreCase = false, bool ignoreLineEndingDifferences = false, bool ignoreWhiteSpaceDifferences = false)
{
// Start out assuming the one of the values is null
int expectedIndex = -1;
int actualIndex = -1;
int expectedLength = 0;
int actualLength = 0;
if (expected == null)
{
if (actual == null)
{
return;
}
expected = NullDisplayValue;
}
else if (actual == null)
{
actual = NullDisplayValue;
}
else
{
// Walk the string, keeping separate indices since we can skip variable amounts of
// data based on ignoreLineEndingDifferences and ignoreWhiteSpaceDifferences.
expectedIndex = 0;
actualIndex = 0;
expectedLength = expected.Length;
actualLength = actual.Length;
while (expectedIndex < expectedLength && actualIndex < actualLength)
{
char expectedChar = expected[expectedIndex];
char actualChar = actual[actualIndex];
if (ignoreLineEndingDifferences && IsLineEnding(expectedChar) && IsLineEnding(actualChar))
{
expectedIndex = SkipLineEnding(expected, expectedIndex);
actualIndex = SkipLineEnding(actual, actualIndex);
}
else if (ignoreWhiteSpaceDifferences && IsWhiteSpace(expectedChar) && IsWhiteSpace(actualChar))
{
expectedIndex = SkipWhitespace(expected, expectedIndex);
actualIndex = SkipWhitespace(actual, actualIndex);
}
else
{
if (ignoreCase)
{
expectedChar = Char.ToUpperInvariant(expectedChar);
actualChar = Char.ToUpperInvariant(actualChar);
}
if (expectedChar != actualChar)
{
break;
}
expectedIndex++;
actualIndex++;
}
}
}
if (expectedIndex < expectedLength || actualIndex < actualLength)
{
throw new StringEqualException(expected, actual, expectedIndex, actualIndex);
}
}
private static bool IsLineEnding(char c)
{
return c == '\r' || c == '\n';
}
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t';
}
private static int SkipLineEnding(string value, int index)
{
if (value[index] == '\r')
{
++index;
}
if (index < value.Length && value[index] == '\n')
{
++index;
}
return index;
}
private static int SkipWhitespace(string value, int index)
{
while (index < value.Length)
{
switch (value[index])
{
case ' ':
case '\t':
index++;
break;
default:
return index;
}
}
return index;
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.TestCommon;
// No namespace so that these extensions are available for all test classes
public static class TaskExtensions
{
/// <summary>
/// Waits until the given task finishes executing and completes in any of the 3 states.
/// </summary>
/// <param name="task">A task</param>
public static void WaitUntilCompleted(this Task task)
{
if (task == null) throw new ArgumentNullException("task");
task.ContinueWith(prev =>
{
if (prev.IsFaulted)
{
// Observe the exception in the faulted case to avoid an unobserved exception leaking and
// killing the thread finalizer.
var e = prev.Exception;
}
}, TaskContinuationOptions.ExecuteSynchronously).Wait();
}
public static void RethrowFaultedTaskException(this Task task)
{
task.WaitUntilCompleted();
Assert.Equal(TaskStatus.Faulted, task.Status);
throw task.Exception.GetBaseException();
}
}

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.IO;
using System.Reflection;
using Microsoft.TestCommon;
namespace System.Web.WebPages.TestUtils
{
public class TestFile
{
public const string ResourceNameFormat = "{0}.TestFiles.{1}";
public string ResourceName { get; set; }
public Assembly Assembly { get; set; }
public TestFile(string resName, Assembly asm)
{
ResourceName = resName;
Assembly = asm;
}
public static TestFile Create(string localResourceName)
{
return new TestFile(String.Format(ResourceNameFormat, Assembly.GetCallingAssembly().GetName().Name, localResourceName), Assembly.GetCallingAssembly());
}
public Stream OpenRead()
{
Stream strm = Assembly.GetManifestResourceStream(ResourceName);
if (strm == null)
{
Assert.True(false, String.Format("Manifest resource: {0} not found", ResourceName));
}
return strm;
}
public byte[] ReadAllBytes()
{
using (Stream stream = OpenRead())
{
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
return buffer;
}
}
public string ReadAllText()
{
using (StreamReader reader = new StreamReader(OpenRead()))
{
// The .Replace() calls normalize line endings, in case you get \n instead of \r\n
// since all the unit tests rely on the assumption that the files will have \r\n endings.
return reader.ReadToEnd().Replace("\r", "").Replace("\n", "\r\n");
}
}
/// <summary>
/// Saves the file to the specified path.
/// </summary>
public void Save(string filePath)
{
var directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (Stream outStream = File.Create(filePath))
{
using (Stream inStream = OpenRead())
{
inStream.CopyTo(outStream);
}
}
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше