├── .editorconfig ├── .gitattributes ├── .gitignore ├── AutoFixtureLogo.png ├── Build.fsx ├── LICENCE.txt ├── README.md ├── Src ├── AutoFixture.ruleset ├── AutoFixture.snk ├── Common.props ├── Empty.ruleset ├── SemanticComparison.sln ├── SemanticComparison │ ├── FalseSpecification.cs │ ├── Fluent │ │ ├── LikenessSource.cs │ │ └── LikenessSourceFactory.cs │ ├── GlobalSuppressions.cs │ ├── IMemberComparer.cs │ ├── ISpecification.cs │ ├── Likeness.cs │ ├── LikenessException.cs │ ├── LikenessMember.cs │ ├── MemberComparer.cs │ ├── MemberEvaluator.cs │ ├── MemberInfoExtension.cs │ ├── MemberInfoNameComparer.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProxyCreationException.cs │ ├── ProxyGenerator.cs │ ├── ProxyType.cs │ ├── SemanticComparer.cs │ ├── SemanticComparison.csproj │ └── TrueSpecification.cs ├── SemanticComparisonUnitTest │ ├── DelegatingEqualityComparer.cs │ ├── DelegatingMemberComparer.cs │ ├── DelegatingSpecification.cs │ ├── DependencyConstraints.cs │ ├── FalseSpecificationTest.cs │ ├── LikenessExceptionTest.cs │ ├── LikenessSourceTest.cs │ ├── LikenessTest.cs │ ├── MemberComparerTest.cs │ ├── MemberInfoNameComparerTest.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProxyCreationExceptionTest.cs │ ├── SemanticComparerTest.cs │ ├── SemanticComparisonUnitTest.csproj │ ├── TestTypes │ │ ├── AbstractType.cs │ │ ├── AbstractTypeWithNonDefaultConstructor.cs │ │ ├── ComplexClass.cs │ │ ├── CompositeType.cs │ │ ├── ConcreteType.cs │ │ ├── DataErrorInfo.cs │ │ ├── DoubleFieldHolder.cs │ │ ├── DoubleParameterType.cs │ │ ├── DoublePropertyHolder.cs │ │ ├── Entity.cs │ │ ├── EqualityResponder.cs │ │ ├── FieldHolder.cs │ │ ├── PropertyHolder.cs │ │ ├── PublicSealedType.cs │ │ ├── QuadrupleParameterType.cs │ │ ├── SingleParameterType.cs │ │ ├── TripleParameterType.cs │ │ ├── TypeOverridingGetHashCode.cs │ │ ├── TypeWithDifferentParameterTypesAndProperties.cs │ │ ├── TypeWithIdenticalParameterTypesAndProperties.cs │ │ ├── TypeWithIncompatibleAndCompatibleConstructor.cs │ │ ├── TypeWithIndexer.cs │ │ ├── TypeWithOverloadedMembers.cs │ │ ├── TypeWithPrivateDefaultCtorAndOtherCtor.cs │ │ ├── TypeWithPublicFieldsAndProperties.cs │ │ ├── TypeWithSimilarPropertyNamesAndIdenticalPropertyTypes.cs │ │ ├── TypeWithUnorderedProperties.cs │ │ └── ValueObject.cs │ └── TrueSpecificationTest.cs └── TestTypeFoundation │ ├── Properties │ └── AssemblyInfo.cs │ └── TestTypeFoundation.csproj ├── appveyor.yml └── build.cmd /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{cs,fs,fsx}] 4 | indent_size = 4 5 | indent_style = space 6 | 7 | [*.{sln,csproj,fsproj,config,xml}] 8 | indent_size = 2 9 | indent_style = space 10 | 11 | [*.cs] 12 | # Require "this." keyword qualification in code 13 | dotnet_style_qualification_for_field = true:suggestion 14 | dotnet_style_qualification_for_property = true:suggestion 15 | dotnet_style_qualification_for_method = true:suggestion 16 | dotnet_style_qualification_for_event = true:suggestion 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enable automatic line ending conversion for text files on checkout and commit. 2 | # For all extensions that are not being explicitly defined below git will try to guess 3 | # whether file contains text and if so, will convert the line endings. 4 | * text=auto 5 | 6 | # Define all the file extensions for which we should always apply line ending covnersion 7 | *.cs text diff=csharp 8 | *.fs text 9 | *.fsx text 10 | *.config text 11 | *.xml text 12 | 13 | *.sln text 14 | *.csproj text 15 | *.fsproj text 16 | *.props text 17 | *.ruleset text 18 | 19 | *.md text 20 | *.txt text 21 | *.yml text 22 | *.pp text 23 | *.nuspec text 24 | 25 | *.bat text 26 | *.cmd text 27 | *.sh text 28 | 29 | # Define all the binary files that should not be touched 30 | *.dll binary 31 | *.exe binary 32 | *.pdb binary 33 | *.png binary 34 | *.snk binary 35 | *.sigdata binary 36 | *.optdata binary 37 | 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Dd]ebug/ 2 | [Rr]elease/ 3 | [Bb]in/ 4 | [Oo]bj/ 5 | [Hh]elp/ 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | 11 | # DotCover is a Code Coverage Tool 12 | *.dotCover 13 | 14 | # ReSharper is a .NET coding add-in 15 | _ReSharper*/ 16 | *.[Rr]e[Ss]harper 17 | *.DotSettings.user 18 | 19 | # NCrunch 20 | _NCrunch_* 21 | .*crunch*.local.xml 22 | nCrunchTemp_* 23 | 24 | # FAKE - F# Make 25 | .fake/ 26 | 27 | # JetBrains Rider 28 | .idea/ 29 | 30 | # Visual Studio 2015 cache/options directory 31 | .vs/ 32 | 33 | # package files can be ignored because of the NuGet restore 34 | **/packages/* 35 | 36 | # Tmp modified files 37 | *.orig 38 | 39 | # Temp build artifacts and tools 40 | /build/ 41 | -------------------------------------------------------------------------------- /AutoFixtureLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutoFixture/SemanticComparison/6cfcd0b704ee2574f3fab788c5f58f9ed68439ee/AutoFixtureLogo.png -------------------------------------------------------------------------------- /Build.fsx: -------------------------------------------------------------------------------- 1 | #r @"build/tools/FAKE.Core/tools/FakeLib.dll" 2 | 3 | open Fake 4 | open Fake.AppVeyor 5 | open Fake.DotNetCli 6 | open Fake.Testing 7 | open System 8 | open System.Diagnostics; 9 | open System.Text.RegularExpressions 10 | 11 | let buildDir = getBuildParamOrDefault "BuildDir" "build" 12 | let buildToolsDir = buildDir "tools" 13 | let nuGetOutputFolder = buildDir "NuGetPackages" 14 | let nuGetPackages = !! (nuGetOutputFolder "*.nupkg" ) 15 | // Skip symbol packages because NuGet publish symbols automatically when package is published 16 | -- (nuGetOutputFolder "*.symbols.nupkg") 17 | let solutionToBuild = "Src/SemanticComparison.sln" 18 | let configuration = getBuildParamOrDefault "BuildConfiguration" "Release" 19 | let bakFileExt = ".orig" 20 | let repositoryUrlOnGitHubSsh = "git@github.com:AutoFixture/SemanticComparison.git" 21 | let repositoryUrlOnGitHubHttps = "https://github.com/AutoFixture/SemanticComparison.git" 22 | 23 | type BuildVersionCalculationSource = { major: int; minor: int; revision: int; preSuffix: string; 24 | commitsNum: int; sha: string; buildNumber: int } 25 | let getVersionSourceFromGit buildNumber = 26 | // The --fist-parent flag is required to correctly work for vNext branch. 27 | // Example of output for a release tag: v3.50.2-288-g64fd5c5b, for a prerelease tag: v3.50.2-alpha1-288-g64fd5c5b 28 | let desc = Git.CommandHelper.runSimpleGitCommand "" "describe --tags --long --abbrev=40 --first-parent --match=v*" 29 | 30 | // Previously repository contained a few broken tags like "v.3.21.1". They were removed, but could still exist 31 | // in forks. We handle them as well to not fail on such repositories. 32 | let result = Regex.Match(desc, 33 | @"^v(\.)?(?\d+)\.(?\d+)\.(?\d+)(?
-\w+\d*)?-(?\d+)-g(?[a-z0-9]+)$",
 34 |                              RegexOptions.IgnoreCase)
 35 |                       .Groups
 36 | 
 37 |     let getMatch (name:string) = result.[name].Value
 38 | 
 39 |     { major = getMatch "maj" |> int
 40 |       minor = getMatch "min" |> int
 41 |       revision = getMatch "rev" |> int
 42 |       preSuffix = getMatch "pre"
 43 |       commitsNum = getMatch "num" |> int
 44 |       sha = getMatch "sha"
 45 |       buildNumber = buildNumber
 46 |     }
 47 | 
 48 | type BuildVersionInfo = { assemblyVersion:string; fileVersion:string; infoVersion:string; nugetVersion:string; 
 49 |                           source: Option }
 50 | let calculateVersion source =
 51 |     let s = source
 52 |     let (major, minor, revision, preReleaseSuffix, commitsNum, sha, buildNumber) =
 53 |         (s.major, s.minor, s.revision, s.preSuffix, s.commitsNum, s.sha, s.buildNumber)
 54 | 
 55 |     let assemblyVersion = sprintf "%d.%d.0.0" major minor
 56 |     let fileVersion = sprintf "%d.%d.%d.%d" major minor revision buildNumber
 57 |     
 58 |     // If number of commits since last tag is greater than zero, we append another identifier with number of commits.
 59 |     // The produced version is larger than the last tag version.
 60 |     // If we are on a tag, we use version without modification.
 61 |     // Examples of output: 3.50.2.1, 3.50.2.215, 3.50.1-rc1.3, 3.50.1-rc3.35
 62 |     let nugetVersion = match commitsNum with
 63 |                        | 0 -> sprintf "%d.%d.%d%s" major minor revision preReleaseSuffix
 64 |                        | _ -> sprintf "%d.%d.%d%s.%d" major minor revision preReleaseSuffix commitsNum
 65 | 
 66 |     let infoVersion = match commitsNum with
 67 |                       | 0 -> nugetVersion
 68 |                       | _ -> sprintf "%s-%s" nugetVersion sha
 69 | 
 70 |     { assemblyVersion=assemblyVersion; fileVersion=fileVersion; infoVersion=infoVersion; nugetVersion=nugetVersion; 
 71 |       source = Some source }
 72 | 
 73 | // Calculate version that should be used for the build. Define globally as data might be required by multiple targets.
 74 | // Please never name the build parameter with version as "Version" - it might be consumed by the MSBuild, override 
 75 | // the defined properties and break some tasks (e.g. NuGet restore).
 76 | let mutable buildVersion = match getBuildParamOrDefault "BuildVersion" "git" with
 77 |                            | "git"       -> getBuildParamOrDefault "BuildNumber" "0"
 78 |                                             |> int
 79 |                                             |> getVersionSourceFromGit
 80 |                                             |> calculateVersion
 81 | 
 82 |                            | assemblyVer -> { assemblyVersion = assemblyVer
 83 |                                               fileVersion = getBuildParamOrDefault "BuildFileVersion" assemblyVer
 84 |                                               infoVersion = getBuildParamOrDefault "BuildInfoVersion" assemblyVer
 85 |                                               nugetVersion = getBuildParamOrDefault "BuildNugetVersion" assemblyVer
 86 |                                               source = None }
 87 | 
 88 | let setVNextBranchVersion vNextVersion =
 89 |     buildVersion <-
 90 |         match buildVersion.source with
 91 |         // Don't update version if it was explicitly specified
 92 |         | None                                -> buildVersion
 93 |         // Don't update version if tag with current major version is already present (e.g. rc is released)
 94 |         | Some s when s.major >= vNextVersion -> buildVersion
 95 |         | Some source                         -> 
 96 |             // The trick is the "git describe" command contains the --first-parent flag.
 97 |             // Because of that git matched the last release tag before the fork was created and calculated number
 98 |             // of commits since that release. We are perfectly fine, as this number will constantly increase only.
 99 |             // Set version to X.0.0-alpha.NUM, where X - major version, NUM - commits since last release before fork
100 |             { source with major = vNextVersion
101 |                           minor = 0
102 |                           revision = 0
103 |                           preSuffix = "-alpha" }
104 |             |> calculateVersion
105 | 
106 | let mutable enableSourceLink = false
107 | 
108 | let runMsBuild target configuration properties =
109 |     let verbosity = match getBuildParam "BuildVerbosity" |> toLower with
110 |                     | "quiet" | "q"         -> Quiet
111 |                     | "minimal" | "m"       -> Minimal
112 |                     | "normal" | "n"        -> Normal
113 |                     | "detailed" | "d"      -> Detailed
114 |                     | "diagnostic" | "diag" -> Diagnostic
115 |                     | _ -> Minimal
116 | 
117 |     let configProperty = match configuration with
118 |                          | Some c -> [ "Configuration", c ]
119 |                          | _ -> []
120 | 
121 |     let sourceLinkCreatePropertyValue = match enableSourceLink with
122 |                                         | true  -> "true"
123 |                                         | false -> "false"
124 | 
125 |     let properties = configProperty @ properties
126 |                      @ [ "AssemblyVersion", buildVersion.assemblyVersion
127 |                          "FileVersion", buildVersion.fileVersion
128 |                          "InformationalVersion", buildVersion.infoVersion
129 |                          "PackageVersion", buildVersion.nugetVersion
130 |                          "SourceLinkCreateOverride", sourceLinkCreatePropertyValue ]
131 | 
132 |     solutionToBuild
133 |     |> build (fun p -> { p with MaxCpuCount = Some None
134 |                                 Verbosity = Some verbosity
135 |                                 Targets = [ target ]
136 |                                 Properties = properties })
137 | 
138 | let cleanBuild configuration = runMsBuild "Clean" (Some configuration) []
139 | let rebuild configuration = runMsBuild "Rebuild" (Some configuration) []
140 | 
141 | Target "CleanAll"               DoNothing 
142 | Target "CleanVerify"            (fun _ -> cleanBuild "Verify")
143 | Target "CleanRelease"           (fun _ -> cleanBuild configuration)
144 | 
145 | Target "RestoreNuGetPackages" (fun _ -> runMsBuild "Restore" None [])
146 | 
147 | Target "EnableSourceLinkGeneration" (fun _ ->
148 |     let areNotEqual a b = String.Equals(a, b, StringComparison.OrdinalIgnoreCase) |> not
149 | 
150 |     // A set of sanity checks to fail with meaningful errors.
151 |     let originUrl = Git.CommandHelper.runSimpleGitCommand "" "config --get remote.origin.url"
152 |     if ((areNotEqual originUrl repositoryUrlOnGitHubSsh) && (areNotEqual originUrl repositoryUrlOnGitHubHttps)) then
153 |         failwithf 
154 |             "Current repository has invalid git origin URL and will produce correct SourceLink info. Expected: '%s' or '%s'. Current: '%s'."
155 |             repositoryUrlOnGitHubSsh
156 |             repositoryUrlOnGitHubHttps
157 |             originUrl
158 |     
159 |     let lineEndingConversion = Git.CommandHelper.runSimpleGitCommand "" "config --get core.autocrlf"
160 |     if(areNotEqual lineEndingConversion "input") then
161 |         failwithf "For correct SourceLink work git line conversion should be set to 'input'. Current: '%s'." lineEndingConversion
162 | 
163 |     enableSourceLink <- true
164 | )
165 | 
166 | Target "Verify" (fun _ -> rebuild "Verify")
167 | 
168 | Target "BuildOnly" (fun _ -> rebuild configuration)
169 | Target "TestOnly" (fun _ ->
170 |     let findTestProjects pattern = System.IO.Directory.GetDirectories("Src", pattern)
171 |     let getTestAssemblies framework projDirs =
172 |         projDirs
173 |         |> Seq.map (fun proj -> !! (sprintf "bin/%s/%s/*Test.dll" configuration framework)
174 |                                 |> SetBaseDir proj)
175 |         |> Seq.collect id
176 | 
177 |     let xUnitTestProjects = findTestProjects "*Test" 
178 | 
179 |     xUnitTestProjects
180 |     |> Seq.iter (fun projPath ->
181 |         DotNetCli.RunCommand (fun p -> { p with WorkingDir = projPath })
182 |                              (sprintf 
183 |                                  "test --no-build --configuration %s"
184 |                                  configuration)
185 |     )
186 | )
187 | 
188 | Target "Build" DoNothing
189 | Target "Test"  DoNothing
190 | 
191 | Target "CleanNuGetPackages" (fun _ ->
192 |     CleanDir nuGetOutputFolder
193 | )
194 | 
195 | Target "NuGetPack" (fun _ ->
196 |     // Pack projects using MSBuild
197 |     runMsBuild "Pack" (Some configuration) [ "IncludeSource", "true"
198 |                                              "IncludeSymbols", "true"
199 |                                              "PackageOutputPath", FullName nuGetOutputFolder
200 |                                              "NoBuild", "true" ]
201 | )
202 | 
203 | let publishPackagesWithSymbols packageFeed symbolFeed accessKey =
204 |     nuGetPackages
205 |     |> Seq.map (fun pkg ->
206 |         let meta = GetMetaDataFromPackageFile pkg
207 |         meta.Id, meta.Version
208 |     )
209 |     |> Seq.iter (fun (id, version) -> NuGetPublish (fun p -> { p with Project = id
210 |                                                                       Version = version
211 |                                                                       OutputPath = nuGetOutputFolder
212 |                                                                       PublishUrl = packageFeed
213 |                                                                       AccessKey = accessKey
214 |                                                                       SymbolPublishUrl = symbolFeed
215 |                                                                       SymbolAccessKey = accessKey
216 |                                                                       WorkingDir = nuGetOutputFolder
217 |                                                                       ToolPath = buildToolsDir  "nuget.exe" }))
218 | 
219 | Target "PublishNuGetPublic" (fun _ ->
220 |     let feed = "https://www.nuget.org/api/v2/package"
221 |     let key = getBuildParam "NuGetPublicKey"
222 | 
223 |     publishPackagesWithSymbols feed "" key
224 | )
225 | 
226 | Target "PublishNuGetPrivate" (fun _ ->
227 |     let packageFeed = "https://www.myget.org/F/autofixture/api/v2/package"
228 |     let symbolFeed = "https://www.myget.org/F/autofixture/symbols/api/v2/package"
229 |     let key = getBuildParam "NuGetPrivateKey"
230 | 
231 |     publishPackagesWithSymbols packageFeed symbolFeed key
232 | )
233 | 
234 | Target "CompleteBuild"   DoNothing
235 | Target "PublishNuGetAll" DoNothing
236 | 
237 | "CleanVerify"  ==> "CleanAll"
238 | "CleanRelease" ==> "CleanAll"
239 | 
240 | "CleanAll"                   ==> "Verify"
241 | "RestoreNuGetPackages"       ==> "Verify"
242 | "EnableSourceLinkGeneration" ?=> "Verify"
243 | 
244 | "Verify"                             ==> "Build"
245 | "BuildOnly"                          ==> "Build"
246 | 
247 | "BuildOnly"              ==> "TestOnly"
248 | 
249 | "Build"    ==> "Test"
250 | "TestOnly" ==> "Test"
251 | 
252 | "CleanNuGetPackages" ==> "NuGetPack"
253 | "Test"               ==> "NuGetPack"
254 | 
255 | "NuGetPack" ==> "CompleteBuild"
256 | 
257 | "NuGetPack"                  ==> "PublishNuGetPublic"
258 | "EnableSourceLinkGeneration" ==> "PublishNuGetPublic"
259 | 
260 | "NuGetPack"                  ==> "PublishNuGetPrivate"
261 | "EnableSourceLinkGeneration" ==> "PublishNuGetPrivate"
262 | 
263 | "PublishNuGetPublic"  ==> "PublishNuGetAll"
264 | "PublishNuGetPrivate" ==> "PublishNuGetAll"
265 | 
266 | // ==============================================
267 | // ================== AppVeyor ==================
268 | // ==============================================
269 | 
270 | // Add helper to identify whether current trigger is PR
271 | type AppVeyorEnvironment with
272 |     static member IsPullRequest = isNotNullOrEmpty AppVeyorEnvironment.PullRequestNumber
273 | 
274 | type AppVeyorTrigger = SemVerTag | CustomTag | PR | VNextBranch | Unknown
275 | let anAppVeyorTrigger =
276 |     let tag = if AppVeyorEnvironment.RepoTag then Some AppVeyorEnvironment.RepoTagName else None
277 |     let isPR = AppVeyorEnvironment.IsPullRequest
278 |     let branch = if isNotNullOrEmpty AppVeyorEnvironment.RepoBranch then Some AppVeyorEnvironment.RepoBranch else None
279 | 
280 |     match tag, isPR, branch with
281 |     | Some t, _, _ when "v\d+.*" >** t -> SemVerTag
282 |     | Some _, _, _                     -> CustomTag
283 |     | _, true, _                       -> PR
284 |     // Branch name should be checked after the PR flag, because for PR it's set to the upstream branch name.
285 |     | _, _, Some br when "v\d+" >** br -> VNextBranch
286 |     | _                                -> Unknown
287 | 
288 | // Print state info at the very beginning
289 | if buildServer = BuildServer.AppVeyor 
290 |    then logfn "[AppVeyor state] Is tag: %b, tag name: '%s', is PR: %b, branch name: '%s', trigger: %A"
291 |               AppVeyorEnvironment.RepoTag 
292 |               AppVeyorEnvironment.RepoTagName 
293 |               AppVeyorEnvironment.IsPullRequest
294 |               AppVeyorEnvironment.RepoBranch
295 |               anAppVeyorTrigger
296 | 
297 | Target "AppVeyor_SetVNextVersion" (fun _ ->
298 |     // vNext branch has the following name: "vX", where X is the next version
299 |     AppVeyorEnvironment.RepoBranch.Substring(1) 
300 |     |> int
301 |     |> setVNextBranchVersion
302 | )
303 | 
304 | Target "AppVeyor" (fun _ ->
305 |     //Artifacts might be deployable, so we update build version to find them later by file version
306 |     if not AppVeyorEnvironment.IsPullRequest then UpdateBuildVersion buildVersion.fileVersion
307 | )
308 | 
309 | "AppVeyor_SetVNextVersion" =?> ("Verify", anAppVeyorTrigger = VNextBranch)
310 | 
311 | // Add logic to resolve action based on current trigger info
312 | dependency "AppVeyor" <| match anAppVeyorTrigger with
313 |                          | SemVerTag                -> "PublishNuGetPublic"
314 |                          | VNextBranch              -> "PublishNuGetPrivate"
315 |                          | PR | CustomTag | Unknown -> "CompleteBuild"
316 | "EnableSourceLinkGeneration" ==> "AppVeyor"
317 | 
318 | // ========= ENTRY POINT =========
319 | RunTargetOrDefault "CompleteBuild"
320 | 


--------------------------------------------------------------------------------
/LICENCE.txt:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2013 Mark Seemann
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
 6 | this software and associated documentation files (the "Software"), to deal in
 7 | the Software without restriction, including without limitation the rights to
 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | [![Build status](https://ci.appveyor.com/api/projects/status/1fgr4ijfcaoijfs2?svg=true)](https://ci.appveyor.com/project/AutoFixture/semanticcomparison) [![NuGet version](https://img.shields.io/nuget/v/SemanticComparison.svg)](https://www.nuget.org/packages/SemanticComparison)  AutoFixture
 2 | 
 3 | # Announcement - v4 was released 🎈
 4 | 
 5 | ## Assembly name and namespace
 6 | 
 7 | Recently the ownership of this project has been passed from Mark Seemann to maintainers of the AutoFixture organization. To reflect that change the default namespace prefix and assembly name were changed from `Ploeh.SemanticComparison` to `SemanticComparison`. Please use the text replace feature of your IDE to quickly fix all the namespace imports.
 8 | 
 9 | ## Project relocation
10 | 
11 | The SemanticComparsion project has been extracted from the [AutoFixture](https://github.com/AutoFixture/AutoFixture) repository to its own repository. The primary goal of this change is to improve the release management, so the AutoFixture product releases don't produce new verisons of the SemanticComparison package. SemanticComparison is a totally separate product without any dependencies on the AutoFixture, so now it could live in its own nest :blush:
12 | 
13 | Refer to the old repository to find the issue and pull request history.
14 | 
15 | # SemanticComparison
16 | 
17 | SemanticComparison makes it easier to compare instances of various objects to each other. Instead of performing a normal equality comparison, SemanticComparison compares objects that look semantically similar - even if they are of different types.
18 | 
19 | ## .NET platforms compatibility table
20 | 
21 | | Product            | .NET Framework            | .NET Standard                 |
22 | | ------------------ | ------------------------  | ----------------------------- |
23 | | SemanticComparison | :heavy_check_mark: 4.5.2  | :heavy_check_mark: 1.5, 2.0   |
24 | 
25 | ## Downloads
26 | 
27 | SemanticComparison is available via NuGet only. Use the Package Manager to install the `SemanticComparison` package.
28 | 
29 | ## Versioning
30 | 
31 | AutoFixture follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html) for the public releases (published to the [nuget.org](https://www.nuget.org/)).
32 | 
33 | ## Build
34 | 
35 | SemanticComparison uses [FAKE](http://fsharp.github.io/FAKE/) as a build engine. If you would like to build the SemanticComparison locally, run the `Build.cmd` file and wait for the result.
36 | 
37 | The repository state (the last tag name and number of commits since the last tag) is used to determine the build version. If you would like to override the auto-generated SemanticComparison version, pass the `BuildVersion` parameter to the `Build.cmd` file. For example:
38 | ```
39 | Build.cmd BuildVersion=4.0.0
40 | ```
41 | 
42 | Refer to the [Build.fsx](Build.fsx) file to get information about all the supported build keys.
43 | 
44 | 


--------------------------------------------------------------------------------
/Src/AutoFixture.ruleset:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |   
  5 |     
  6 |     
  7 |     
  8 |     
  9 |     
 10 |     
 11 |     
 12 |     
 13 |     
 14 |     
 15 |     
 16 |     
 17 |     
 18 |     
 19 |     
 20 |     
 21 |     
 22 |     
 23 |     
 24 |     
 25 |     
 26 |     
 27 |     
 28 |     
 29 |     
 30 |     
 31 |     
 32 |     
 33 |     
 34 |     
 35 |     
 36 |     
 37 |     
 38 |     
 39 |     
 40 |     
 41 |     
 42 |     
 43 |     
 44 |     
 45 |     
 46 |     
 47 |     
 48 |     
 49 |     
 50 |     
 51 |     
 52 |     
 53 |     
 54 |     
 55 |     
 56 |     
 57 |     
 58 |     
 59 |     
 60 |     
 61 |     
 62 |     
 63 |     
 64 |     
 65 |     
 66 |     
 67 |     
 68 |     
 69 |     
 70 |     
 71 |     
 72 |     
 73 |     
 74 |     
 75 |     
 76 |     
 77 |     
 78 |     
 79 |     
 80 |     
 81 |     
 82 |     
 83 |     
 84 |     
 85 |     
 86 |     
 87 |     
 88 |     
 89 |     
 90 |     
 91 |     
 92 |     
 93 |     
 94 |     
 95 |     
 96 |     
 97 |     
 98 |     
 99 |     
100 |     
101 |     
102 |     
103 |     
104 |     
105 |     
106 |     
107 |     
108 |     
109 |     
110 |     
111 |     
112 |     
113 |     
114 |     
115 |     
116 |     
117 |     
118 |     
119 |     
120 |     
121 |     
122 |     
123 |     
124 |     
125 |     
126 |     
127 |     
128 |     
129 |     
130 |     
131 |     
132 |     
133 |     
134 |     
135 |     
136 |     
137 |     
138 |     
139 |     
140 |     
141 |     
142 |     
143 |     
144 |     
145 |     
146 |     
147 |     
148 |     
149 |     
150 |     
151 |     
152 |     
153 |     
154 |     
155 |     
156 |     
157 |     
158 |     
159 |     
160 |     
161 |     
162 |     
163 |     
164 |     
165 |     
166 |     
167 |     
168 |     
169 |     
170 |     
171 |     
172 |     
173 |     
174 |     
175 |     
176 |     
177 |     
178 |     
179 |     
180 |     
181 |     
182 |     
183 |     
184 |     
185 |     
186 |     
187 |     
188 |     
189 |     
190 |     
191 |     
192 |     
193 |     
194 |     
195 |     
196 |     
197 |     
198 |     
199 |     
200 |     
201 |     
202 |     
203 |     
204 |     
205 |     
206 |     
207 |     
208 |     
209 |     
210 |     
211 |     
212 |     
213 |     
214 |     
215 |     
216 |     
217 |     
218 |     
219 |     
220 |     
221 |     
222 |     
223 |     
224 |     
225 |     
226 |     
227 |     
228 |     
229 |     
230 |     
231 |     
232 |     
233 |     
234 |     
235 |     
236 |     
237 |   
238 |   
239 |     
240 |   
241 |   
242 |     
243 |   
244 |   
245 |     
246 |   
247 | 


--------------------------------------------------------------------------------
/Src/AutoFixture.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AutoFixture/SemanticComparison/6cfcd0b704ee2574f3fab788c5f58f9ed68439ee/Src/AutoFixture.snk


--------------------------------------------------------------------------------
/Src/Common.props:
--------------------------------------------------------------------------------
 1 | 
 2 |   
 3 |     SemanticComparison
 4 |     AutoFixture
 5 |     Copyright © AutoFixture 2011
 6 |     false
 7 |     false
 8 | 
 9 |     en-US
10 |     $(MSBuildThisFileDirectory)\AutoFixture.ruleset
11 |     IOperation
12 | 
13 |     True
14 |     $(MSBuildThisFileDirectory)\AutoFixture.snk
15 | 
16 |     Debug;Release;Verify
17 | 
18 |     
19 |     Mark Seemann,AutoFixture
20 |     https://github.com/AutoFixture/SemanticComparison
21 |     MIT
22 |     https://raw.githubusercontent.com/AutoFixture/SemanticComparison/master/AutoFixtureLogo.png
23 |   
24 | 
25 |   
26 |     
27 |       
28 |     
29 |     
30 |       
31 |         <_IsFullFramework>true
32 |         $(DefineConstants);SYSTEM_RUNTIME_SERIALIZATION;SYSTEM_COMPONENTSETTINGS_DATAERRORINFO;SYSTEM_REFLECTION_EMIT_DYNAMICASSEMBLY_SAVE
33 |       
34 |     
35 |   
36 | 
37 |   
38 |     
39 |       
40 |         true
41 |         
42 |         pdbonly
43 |         portable
44 |       
45 |     
46 |     
47 |       
48 |         $(DefineConstants);CODE_ANALYSIS
49 |         true
50 |         pdbonly
51 |         
52 |         true
53 |         true
54 |         true
55 |         true
56 |         true
57 |       
58 |     
59 |   
60 | 
61 |   
62 |     
63 |   
64 |   
65 |   
66 |     
67 |     
68 |   
69 |   
70 |     $(SourceLinkCreateOverride)
71 |     error
72 |     error
73 |     true
74 |   
75 | 
76 | 


--------------------------------------------------------------------------------
/Src/Empty.ruleset:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |   
  5 |     
  6 |     
  7 |     
  8 |     
  9 |     
 10 |     
 11 |     
 12 |     
 13 |     
 14 |     
 15 |     
 16 |     
 17 |     
 18 |     
 19 |     
 20 |     
 21 |     
 22 |     
 23 |     
 24 |     
 25 |     
 26 |     
 27 |     
 28 |     
 29 |     
 30 |     
 31 |     
 32 |     
 33 |     
 34 |     
 35 |     
 36 |     
 37 |     
 38 |     
 39 |     
 40 |     
 41 |     
 42 |     
 43 |     
 44 |     
 45 |     
 46 |     
 47 |     
 48 |     
 49 |     
 50 |     
 51 |     
 52 |     
 53 |     
 54 |     
 55 |     
 56 |     
 57 |     
 58 |     
 59 |     
 60 |     
 61 |     
 62 |     
 63 |     
 64 |     
 65 |     
 66 |     
 67 |     
 68 |     
 69 |     
 70 |     
 71 |     
 72 |     
 73 |     
 74 |     
 75 |     
 76 |     
 77 |     
 78 |     
 79 |     
 80 |     
 81 |     
 82 |     
 83 |     
 84 |     
 85 |     
 86 |     
 87 |     
 88 |     
 89 |     
 90 |     
 91 |     
 92 |     
 93 |     
 94 |     
 95 |     
 96 |     
 97 |     
 98 |     
 99 |     
100 |     
101 |     
102 |     
103 |     
104 |     
105 |     
106 |     
107 |     
108 |     
109 |     
110 |     
111 |     
112 |     
113 |     
114 |     
115 |     
116 |     
117 |     
118 |     
119 |     
120 |     
121 |     
122 |     
123 |     
124 |     
125 |     
126 |     
127 |     
128 |     
129 |     
130 |     
131 |     
132 |     
133 |     
134 |     
135 |     
136 |     
137 |     
138 |     
139 |     
140 |     
141 |     
142 | 	
143 |     
144 |     
145 |     
146 |     
147 |     
148 |     
149 |     
150 |     
151 |     
152 |     
153 |     
154 |     
155 |     
156 |     
157 |     
158 |     
159 |     
160 |     
161 |     
162 |     
163 |     
164 |     
165 |     
166 |     
167 |     
168 |     
169 |     
170 |     
171 |     
172 |     
173 |     
174 |     
175 |     
176 |     
177 |     
178 |     
179 |     
180 |     
181 |     
182 |     
183 |     
184 |     
185 |     
186 |     
187 |     
188 |     
189 |     
190 |     
191 |     
192 |     
193 |     
194 |     
195 |     
196 |     
197 |     
198 |     
199 |     
200 |     
201 |     
202 |     
203 |     
204 |     
205 |     
206 |     
207 |     
208 |     
209 |     
210 |     
211 |     
212 |     
213 |     
214 |     
215 |     
216 |     
217 |     
218 |     
219 |     
220 |     
221 |     
222 |     
223 |     
224 |     
225 |     
226 |     
227 |     
228 |     
229 |     
230 |     
231 |     
232 |     
233 |     
234 |     
235 |     
236 |     
237 |     
238 |   
239 |   
240 |     
241 |     
242 |     
243 |     
244 |     
245 |     
246 |     
247 |     
248 |     
249 |     
250 |     
251 |     
252 |     
253 |     
254 |     
255 |     
256 |     
257 |     
258 |     
259 |     
260 |     
261 |     
262 |     
263 |     
264 |     
265 |     
266 |     
267 |     
268 |     
269 |     
270 |     
271 |     
272 |     
273 |     
274 |     
275 |     
276 |     
277 |     
278 |     
279 |     
280 |     
281 |     
282 |     
283 |     
284 |     
285 |     
286 |     
287 |     
288 |     
289 |     
290 |     
291 |     
292 |     
293 |     
294 |     
295 |     
296 |     
297 |     
298 |     
299 |     
300 |     
301 |     
302 |     
303 |     
304 |     
305 |     
306 |     
307 |     
308 |     
309 |     
310 |     
311 |     
312 |     
313 |     
314 |     
315 |     
316 |     
317 |     
318 |     
319 |     
320 |     
321 |     
322 |     
323 |     
324 |     
325 |     
326 |     
327 |     
328 |     
329 |     
330 |     
331 |     
332 |     
333 |     
334 |     
335 |     
336 |     
337 |     
338 |     
339 |     
340 |     
341 |     
342 |     
343 |     
344 |     
345 |     
346 |     
347 |     
348 |     
349 |     
350 |     
351 |     
352 |     
353 |     
354 |     
355 |     
356 |     
357 |     
358 |     
359 |     
360 |     
361 |     
362 |     
363 |     
364 |     
365 |     
366 |     
367 |     
368 |     
369 |     
370 |     
371 |     
372 |     
373 |     
374 |     
375 |     
376 |     
377 |     
378 |     
379 |     
380 |     
381 |     
382 |     
383 |     
384 |     
385 |     
386 |     
387 |     
388 |     
389 |     
390 |     
391 |     
392 |     
393 |     
394 |     
395 |     
396 |     
397 |     
398 |     
399 |     
400 |     
401 |     
402 |     
403 |     
404 |     
405 |     
406 |     
407 |     
408 |     
409 |     
410 |     
411 |     
412 |     
413 |     
414 |     
415 |     
416 |     
417 |     
418 |     
419 |     
420 |     
421 |     
422 |     
423 |     
424 |     
425 |     
426 |     
427 |     
428 |     
429 |     
430 |     
431 |     
432 |     
433 |     
434 |     
435 |     
436 |     
437 |     
438 |     
439 |     
440 |     
441 |     
442 |     
443 |     
444 |     
445 |     
446 |     
447 |     
448 |     
449 |     
450 |     
451 |     
452 |     
453 |     
454 |     
455 |     
456 |     
457 |     
458 |     
459 |     
460 |     
461 |     
462 |     
463 |     
464 |     
465 |     
466 |     
467 |     
468 |     
469 |     
470 |     
471 |     
472 |     
473 |     
474 |     
475 |     
476 |     
477 |     
478 |     
479 |     
480 |     
481 |     
482 |     
483 |     
484 |     
485 |     
486 |     
487 |     
488 |     
489 |     
490 |     
491 |     
492 |     
493 |     
494 |     
495 |     
496 |     
497 |     
498 |     
499 |     
500 |     
501 |     
502 |     
503 |     
504 |     
505 |     
506 |     
507 |     
508 |     
509 |     
510 |     
511 |     
512 |     
513 |     
514 |     
515 |     
516 |     
517 |     
518 |     
519 |     
520 |     
521 |     
522 |     
523 |     
524 |     
525 |     
526 |     
527 |     
528 |     
529 |     
530 |     
531 |     
532 |     
533 |     
534 |     
535 |     
536 |     
537 |     
538 |     
539 |     
540 |     
541 |     
542 |     
543 |     
544 |     
545 |     
546 |     
547 |     
548 |     
549 |     
550 |     
551 |     
552 |     
553 |     
554 |     
555 |     
556 |     
557 |     
558 |     
559 |     
560 |     
561 |     
562 |     
563 |     
564 |     
565 |     
566 |     
567 |     
568 |     
569 |     
570 |     
571 |     
572 |     
573 |     
574 |     
575 |     
576 |     
577 |     
578 |     
579 |     
580 |     
581 |     
582 |     
583 |     
584 |     
585 |     
586 |     
587 |     
588 |     
589 |     
590 |     
591 |   
592 |   
593 |     
594 |   
595 |   
596 |     
597 |   
598 |   
599 |     
600 |   
601 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison.sln:
--------------------------------------------------------------------------------
 1 | 
 2 | Microsoft Visual Studio Solution File, Format Version 12.00
 3 | # Visual Studio 15
 4 | VisualStudioVersion = 15.0.27004.2002
 5 | MinimumVisualStudioVersion = 10.0.40219.1
 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SemanticComparison", "SemanticComparison\SemanticComparison.csproj", "{0FC5862D-CCF5-4C56-8819-BF5051ECB855}"
 7 | EndProject
 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SemanticComparisonUnitTest", "SemanticComparisonUnitTest\SemanticComparisonUnitTest.csproj", "{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}"
 9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{694F66E9-29BA-4EAF-8B98-F9241A07BB5C}"
11 | 	ProjectSection(SolutionItems) = preProject
12 | 		..\.editorconfig = ..\.editorconfig
13 | 		Common.props = Common.props
14 | 	EndProjectSection
15 | EndProject
16 | Global
17 | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | 		Debug|Any CPU = Debug|Any CPU
19 | 		Release|Any CPU = Release|Any CPU
20 | 		Verify|Any CPU = Verify|Any CPU
21 | 	EndGlobalSection
22 | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Release|Any CPU.Build.0 = Release|Any CPU
27 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Verify|Any CPU.ActiveCfg = Verify|Any CPU
28 | 		{0FC5862D-CCF5-4C56-8819-BF5051ECB855}.Verify|Any CPU.Build.0 = Verify|Any CPU
29 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Release|Any CPU.Build.0 = Release|Any CPU
33 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Verify|Any CPU.ActiveCfg = Verify|Any CPU
34 | 		{D32CA074-F5AE-42F6-B24B-C5018AB41DB4}.Verify|Any CPU.Build.0 = Verify|Any CPU
35 | 	EndGlobalSection
36 | 	GlobalSection(SolutionProperties) = preSolution
37 | 		HideSolutionNode = FALSE
38 | 	EndGlobalSection
39 | 	GlobalSection(ExtensibilityGlobals) = postSolution
40 | 		SolutionGuid = {6EC72A59-D976-4FE0-871B-0C48FCE5FAC7}
41 | 	EndGlobalSection
42 | EndGlobal
43 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/FalseSpecification.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparison
 2 | {
 3 |     /// 
 4 |     /// A  that is always .
 5 |     /// 
 6 |     public class FalseSpecification : ISpecification
 7 |     {
 8 |         /// 
 9 |         /// Determines whether a candidate is satisfied by the Specification.
10 |         /// 
11 |         /// The candidate.
12 |         /// 
13 |         public bool IsSatisfiedBy(T candidate)
14 |         {
15 |             return false;
16 |         }
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/Fluent/LikenessSource.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparison.Fluent
 2 | {
 3 |     /// 
 4 |     /// Defines the source-side of a .
 5 |     /// 
 6 |     /// The type of the source value.
 7 |     public class LikenessSource
 8 |     {
 9 |         private readonly TSource value;
10 | 
11 |         /// 
12 |         /// Initializes a new instance of the  class with the supplied
13 |         /// value.
14 |         /// 
15 |         /// The source value.
16 |         public LikenessSource(TSource value)
17 |         {
18 |             this.value = value;
19 |         }
20 | 
21 |         /// 
22 |         /// Creates a  instance.
23 |         /// 
24 |         /// The data type of the destination.
25 |         /// 
26 |         /// A new instance of  that contains the
27 |         /// source value defined in the constructor.
28 |         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "Although this CA warning should never be suppressed, this particular usage scenario has been discussed and accepted on the FxCop DL.")]
29 |         public Likeness OfLikeness()
30 |         {
31 |             return new Likeness(this.value);
32 |         }
33 |     }
34 | }
35 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/Fluent/LikenessSourceFactory.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparison.Fluent
 2 | {
 3 |     /// 
 4 |     /// Contains extension methods for working with .
 5 |     /// 
 6 |     public static class LikenessSourceFactory
 7 |     {
 8 |         /// 
 9 |         /// Creates a new  from an object instance.
10 |         /// 
11 |         /// The type of the source value.
12 |         /// The source value.
13 |         /// A new  instance.
14 |         /// 
15 |         /// 
16 |         /// This method is particularly handy for anonymous types, since it can use type
17 |         /// inferencing to determine  from the value itself. This is
18 |         /// essentially the only way you can create a 
19 |         /// from the public API when the source value is an instance of an anonymous type.
20 |         /// 
21 |         /// 
22 |         public static LikenessSource AsSource(this TSource value)
23 |         {
24 |             return new LikenessSource(value);
25 |         }
26 |     }
27 | }
28 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
 1 | // This file is used by Code Analysis to maintain SuppressMessage 
 2 | // attributes that are applied to this project. 
 3 | // Project-level suppressions either have no target or are given 
 4 | // a specific target and scoped to a namespace, type, member, etc. 
 5 | //
 6 | // To add a suppression to this file, right-click the message in the 
 7 | // Error List, point to "Suppress Message(s)", and click 
 8 | // "In Project Suppression File". 
 9 | // You do not need to add suppressions to this file manually. 
10 | 
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "SemanticComparison.Fluent", Justification = "These types only exist to support the corner case where you need to build a Likeness from an anonymous type. The extension method should not be available unless explicitly imported.")]
12 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/IMemberComparer.cs:
--------------------------------------------------------------------------------
 1 | using System.Collections;
 2 | using System.Reflection;
 3 | 
 4 | namespace SemanticComparison
 5 | {
 6 |     /// 
 7 |     /// Evaluates requests for comparison of a property and field for equality.
 8 |     /// 
 9 |     public interface IMemberComparer : IEqualityComparer
10 |     {
11 |         /// 
12 |         /// Evaluates a request for comparison of a property.
13 |         /// 
14 |         /// The request for comparison of a property.
15 |         ///  if  is
16 |         /// satisfied by the comparison; otherwise, .
17 |         /// 
18 |         bool IsSatisfiedBy(PropertyInfo request);
19 | 
20 |         /// 
21 |         /// Evaluates a request for comparison of a field.
22 |         /// 
23 |         /// The request for comparison of a field.
24 |         ///   if  is
25 |         /// satisfied by the comparison; otherwise, .
26 |         /// 
27 |         bool IsSatisfiedBy(FieldInfo request);
28 |     }
29 | }


--------------------------------------------------------------------------------
/Src/SemanticComparison/ISpecification.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparison
 2 | {
 3 |     /// 
 4 |     /// A Specification that evaluates candidates.
 5 |     /// 
 6 |     /// The type of candidate to evaluate.
 7 |     public interface ISpecification
 8 |     {
 9 |         /// 
10 |         /// Determines whether the candidate is satisfied by the Specification.
11 |         /// 
12 |         /// The request.
13 |         /// 
14 |         ///  if the candidate is satisfied by the
15 |         /// Specification; otherwise, .
16 |         /// 
17 |         bool IsSatisfiedBy(T candidate);
18 |     }
19 | }


--------------------------------------------------------------------------------
/Src/SemanticComparison/Likeness.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Collections.Generic;
  3 | using System.Globalization;
  4 | using System.Linq;
  5 | using System.Linq.Expressions;
  6 | using System.Reflection;
  7 | 
  8 | namespace SemanticComparison
  9 | {
 10 |     /// 
 11 |     /// Provides convention-based object equality comparison for use when comparing two
 12 |     /// semantically equivalent, but different, objects.
 13 |     /// 
 14 |     /// 
 15 |     /// The type of the source value (against which the destination value will be compared for
 16 |     /// equality).
 17 |     /// 
 18 |     /// 
 19 |     /// The type of the destination value which will be compared for equality against the source
 20 |     /// value.
 21 |     /// 
 22 |     public class Likeness : IEquatable
 23 |     {
 24 |         private readonly SemanticComparer comparer;
 25 | 
 26 |         /// 
 27 |         /// Initializes a new instance of the  class
 28 |         /// with the supplied source value.
 29 |         /// 
 30 |         /// 
 31 |         /// The source value against which destination values will be compared when
 32 |         ///  is invoked.
 33 |         public Likeness(TSource value)
 34 |             : this(value, Enumerable.Empty>(), SemanticComparer.DefaultMembers.Generate)
 35 |         {
 36 |         }
 37 | 
 38 |         internal Likeness(TSource value, IEnumerable> evaluators, Func> defaultMembersGenerator)
 39 |         {
 40 |             this.Value = value;
 41 |             this.comparer = new SemanticComparer(evaluators, defaultMembersGenerator);
 42 |         }
 43 | 
 44 |         /// 
 45 |         /// Gets the source value against which destination values will be compared when
 46 |         ///  is invoked.
 47 |         /// 
 48 |         public TSource Value { get; }
 49 | 
 50 |         /// 
 51 |         /// Creates a dynamic proxy that overrides Equals using Likeness. 
 52 |         /// This method uses the same semantic heuristics, as the default semantic comparison, to map
 53 |         /// values from the source constructor parameters to the destination constructor.
 54 |         /// 
 55 |         public TDestination CreateProxy()
 56 |         {
 57 |             try
 58 |             {
 59 |                 return ProxyGenerator.CreateLikenessProxy(
 60 |                     this.Value,
 61 |                     this.comparer,
 62 |                     SemanticComparer.DefaultMembers.Generate());
 63 |             }
 64 |             catch (TypeLoadException e)
 65 |             {
 66 |                 var message = string.Format(
 67 |                     CultureInfo.CurrentCulture,
 68 |                     "The proxy of {0} could not be created. Access is denied on type, or the base type is sealed. Please see inner exception for more details.",
 69 |                     typeof(TDestination));
 70 |                 throw new ProxyCreationException(message, e);
 71 |             }
 72 |             catch (InvalidOperationException e)
 73 |             {
 74 |                 var message = string.Format(
 75 |                     CultureInfo.CurrentCulture,
 76 |                     "The proxy of {0} could not be created using the same semantic heuristics as the default semantic comparison. In order to create proxies of types with non-parameterless constructor the values from the source constructor must be compatible to the parameters of the destination constructor.",
 77 |                     typeof(TDestination));
 78 |                 throw new ProxyCreationException(message, e);
 79 |             }
 80 |         }
 81 | 
 82 |         /// 
 83 |         /// Determines whether the specified  is semantically equal to the
 84 |         /// current .
 85 |         /// 
 86 |         /// The object to compare against .
 87 |         /// 
 88 |         ///  if  is semantically equal to
 89 |         /// ; otherwise, .
 90 |         /// 
 91 |         public override bool Equals(object obj)
 92 |         {
 93 |             if ((this.Value == null) && (obj == null))
 94 |             {
 95 |                 return true;
 96 |             }
 97 | 
 98 |             if (obj is TDestination)
 99 |             {
100 |                 return this.Equals((TDestination)obj);
101 |             }
102 |             return base.Equals(obj);
103 |         }
104 | 
105 |         /// 
106 |         /// Serves as a hash function for .
107 |         /// 
108 |         /// 
109 |         /// The hash code for , or 0 if the value is .
110 |         /// 
111 |         public override int GetHashCode()
112 |         {
113 |             return this.Value == null ? 0 : this.Value.GetHashCode();
114 |         }
115 | 
116 |         /// 
117 |         /// Turns off implicit default comparison of properties and fields.
118 |         /// 
119 |         /// 
120 |         /// A new  that uses only explicitly defined
121 |         /// comparisons of properties and fields.
122 |         /// 
123 |         public Likeness OmitAutoComparison()
124 |         {
125 |             return new Likeness(this.Value, this.comparer.Evaluators, Enumerable.Empty);
126 |         }
127 | 
128 |         /// 
129 |         /// Verifies that a value matches the encapsulated value, or throws a descriptive exception
130 |         /// if this is not the case.
131 |         /// 
132 |         /// The value to compare against .
133 |         /// 
134 |         ///  does not match .
135 |         /// 
136 |         public void ShouldEqual(TDestination other)
137 |         {
138 |             if ((this.Value == null) && (other == null))
139 |             {
140 |                 return;
141 |             }
142 |             if (other == null)
143 |             {
144 |                 throw new LikenessException("The provided value was null, but an instance was expected.");
145 |             }
146 | 
147 |             var mismatches = (from me in this.comparer.GetEvaluators()
148 |                               where !me.Evaluator(this.Value, other)
149 |                               select me).ToList();
150 |             if (mismatches.Any())
151 |             {
152 |                 var message = this.CreateMismatchMessage(other, mismatches);
153 |                 throw new LikenessException(message);
154 |             }
155 |         }
156 | 
157 |         /// 
158 |         /// Returns a  that represents the contained object.
159 |         /// 
160 |         /// A  representation of the contained object.
161 |         public override string ToString()
162 |         {
163 |             var valueText = this.Value == null ? "null" : this.Value.ToString();
164 |             return string.Format(CultureInfo.CurrentCulture, "Likeness of {0}", valueText);
165 |         }
166 | 
167 |         /// 
168 |         /// Returns a  that can be used to
169 |         /// define custom comparison behavior for a particular property or field.
170 |         /// 
171 |         /// The type of the property or field.
172 |         /// 
173 |         /// An expression that identifies the property or field.
174 |         /// 
175 |         /// 
176 |         /// A new instance of  that represents
177 |         /// the property or field identified by .
178 |         /// 
179 |         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "The explicit use of Expression> enables type inference from the test code. With only the base class LambdaExpression, calling code would have to explicitly spell out the property type as a generic type parameter. This would hurt readability of the calling code.")]
180 |         public LikenessMember With(Expression> propertyPicker)
181 |         {
182 |             if (propertyPicker == null)
183 |             {
184 |                 throw new ArgumentNullException(nameof(propertyPicker));
185 |             }
186 | 
187 |             var me = (MemberExpression)propertyPicker.Body;
188 |             return new LikenessMember(this, me.Member);
189 |         }
190 | 
191 |         /// 
192 |         /// Opt-in of default equality comparison for a specific property or field. Only relevant
193 |         /// if  was previously called.
194 |         /// 
195 |         /// The type of the property or field.
196 |         /// 
197 |         /// An expression that identifies the property or field.
198 |         /// 
199 |         /// 
200 |         /// A new instance of  that explicitly
201 |         /// includes the member identified by  and uses the
202 |         /// default comparison.
203 |         /// 
204 |         public Likeness WithDefaultEquality(Expression> propertyPicker)
205 |         {
206 |             if (propertyPicker == null)
207 |             {
208 |                 throw new ArgumentNullException(nameof(propertyPicker));
209 |             }
210 | 
211 |             var me = (MemberExpression)propertyPicker.Body;
212 |             var f = me.Member.ToEvaluator();
213 |             return this.With(propertyPicker).EqualsWhen(f.Evaluator);
214 |         }
215 | 
216 |         /// 
217 |         /// Returns a new  that ignores a particular
218 |         /// property when comparing values.
219 |         /// 
220 |         /// The type of the property or field to ignore.
221 |         /// 
222 |         /// An expression that identifies the property or field to be ignored.
223 |         /// 
224 |         /// 
225 |         /// A new  that ignores the property
226 |         /// identified by  when determining equality.
227 |         /// 
228 |         public Likeness Without(Expression> propertyPicker)
229 |         {
230 |             return this.With(propertyPicker).EqualsWhen((s, d) => true);
231 |         }
232 | 
233 |         /// 
234 |         /// Determines whether the specified object is semantically equal to the current
235 |         /// .
236 |         /// 
237 |         /// The object to compare against .
238 |         /// 
239 |         ///  if  is semantically equal to
240 |         /// ; otherwise, .
241 |         /// 
242 |         public bool Equals(TDestination other)
243 |         {
244 |             if ((this.Value == null) && (other == null))
245 |             {
246 |                 return true;
247 |             }
248 |             if (other == null)
249 |             {
250 |                 return false;
251 |             }
252 | 
253 |             return this.comparer.Equals(this.Value, other);
254 |         }
255 | 
256 |         internal Likeness AddEvaluator(MemberEvaluator evaluator)
257 |         {
258 |             return new Likeness(this.Value, this.comparer.Evaluators.Concat(new[] { evaluator }), this.comparer.DefaultMembersGenerator);
259 |         }
260 | 
261 |         private string CreateMismatchMessage(TDestination other, IEnumerable> mismatches)
262 |         {
263 |             return string.Concat(
264 |                 new[]
265 |                 {
266 |                     string.Format(CultureInfo.CurrentCulture, "The provided value {0} did not match the expected value {1}. The following members did not match:{2}", this.Value, other, Environment.NewLine)
267 |                 }
268 |                 .Concat(mismatches.Select(me => string.Format(CultureInfo.CurrentCulture, "- {0}.{1}", me.Member.Name, Environment.NewLine)))
269 |                 .ToArray());
270 |         }
271 |     }
272 | 
273 |     /// 
274 |     /// Provides convention-based object equality comparison for use when 
275 |     /// comparing two semantically equivalent objects.
276 |     /// 
277 |     /// 
278 |     /// The type of the value which will be compared for equality.
279 |     /// 
280 |     public class Likeness : IEquatable
281 |     {
282 |         private readonly IEqualityComparer comparer;
283 | 
284 |         /// 
285 |         /// Initializes a new instance of the  
286 |         /// class with the supplied value.
287 |         /// 
288 |         /// The value which will be compared for equality.
289 |         /// 
290 |         public Likeness(T value)
291 |             : this(value, new SemanticComparer())
292 |         {
293 |         }
294 | 
295 |         /// 
296 |         /// Initializes a new instance of the  
297 |         /// class with the supplied value.
298 |         /// 
299 |         /// The value which will be compared for equality.
300 |         /// 
301 |         /// 
302 |         /// The comparer to support the comparison of objects for equality.
303 |         /// 
304 |         public Likeness(T value, IEqualityComparer comparer)
305 |         {
306 |             if (comparer == null)
307 |                 throw new ArgumentNullException(nameof(comparer));
308 | 
309 |             this.Value = value;
310 |             this.comparer = comparer;
311 |         }
312 | 
313 |         /// 
314 |         /// Gets the supplied value which will be compared for equality.
315 |         /// 
316 |         /// 
317 |         /// The supplied value which will be compared for equality.
318 |         /// 
319 |         public T Value { get; }
320 | 
321 |         /// 
322 |         /// Determines whether the specified  is semantically
323 |         /// equal to the current .
324 |         /// 
325 |         /// 
326 |         /// The object to compare against .
327 |         /// 
328 |         /// 
329 |         ///  if  is semantically
330 |         /// equal to ; otherwise, .
331 |         /// 
332 |         public override bool Equals(object obj)
333 |         {
334 |             return (this.Value == null && obj == null)
335 |                 ? true
336 |                 : (obj is T
337 |                     ? this.Equals((T)obj)
338 |                     : base.Equals(obj));
339 |         }
340 | 
341 |         /// 
342 |         /// Serves as a hash function for .
343 |         /// 
344 |         /// 
345 |         /// The hash code for , or 0 if the value is 
346 |         /// .
347 |         /// 
348 |         public override int GetHashCode()
349 |         {
350 |             return this.Value == null 
351 |                 ? 0 
352 |                 : this.Value.GetHashCode();
353 |         }
354 | 
355 |         /// 
356 |         /// Returns a  that represents the contained object.
357 |         /// 
358 |         /// 
359 |         /// A  representation of the contained object.
360 |         /// 
361 |         public override string ToString()
362 |         {
363 |             return string.Format(
364 |                 CultureInfo.CurrentCulture, 
365 |                 "Likeness of {0}", 
366 |                 this.Value == null ? "null" : this.Value.ToString());
367 |         }
368 | 
369 |         /// 
370 |         /// Determines whether the specified object is semantically equal to 
371 |         /// the current .
372 |         /// 
373 |         /// 
374 |         /// The object to compare against .
375 |         /// 
376 |         /// 
377 |         ///  if  is semantically
378 |         /// equal to ; otherwise, .
379 |         /// 
380 |         public bool Equals(T other)
381 |         {
382 |             if (this.Value == null && other == null)
383 |                 return true;
384 | 
385 |             if (other == null)
386 |                 return false;
387 | 
388 |             return this.comparer.Equals(this.Value, other);
389 |         }
390 | 
391 |         /// 
392 |         /// Turns the  into a Resemblance by 
393 |         /// dynamically emitting a derived class that overrides Equals in the 
394 |         /// way that the  (re)defines equality.
395 |         /// 
396 |         /// 
397 |         /// A dynamically emitted derived class that overrides Equals in the 
398 |         /// way that the  (re)defines equality.
399 |         /// 
400 |         /// 
401 |         public T ToResemblance()
402 |         {
403 |             try
404 |             {
405 |                 return ProxyGenerator.CreateLikenessResemblance(this);
406 |             }
407 |             catch (TypeLoadException e)
408 |             {
409 |                 var message = string.Format(
410 |                     CultureInfo.CurrentCulture,
411 |                     "The resemblance of {0} could not be created. Access is denied on type, or the base type is sealed. Please see inner exception for more details.",
412 |                     typeof(T));
413 |                 throw new ProxyCreationException(message, e);
414 |             }
415 |         }
416 |     }
417 | }


--------------------------------------------------------------------------------
/Src/SemanticComparison/LikenessException.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparison
 4 | {
 5 |     /// 
 6 |     /// Represents an error where two semantically comparable instances were expected to match, but
 7 |     /// didn't.
 8 |     /// 
 9 | 
10 | #if SYSTEM_RUNTIME_SERIALIZATION
11 |     [Serializable]
12 | #endif
13 |     public class LikenessException : Exception
14 |     {
15 |         /// 
16 |         /// Initializes a new instance of the  class.
17 |         /// 
18 |         public LikenessException()
19 |         {
20 |         }
21 | 
22 |         /// 
23 |         /// Initializes a new instance of the  class.
24 |         /// 
25 |         /// The message.
26 |         public LikenessException(string message)
27 |             : base(message)
28 |         {
29 |         }
30 | 
31 |         /// 
32 |         /// Initializes a new instance of the  class.
33 |         /// 
34 |         /// The message.
35 |         /// The inner exception.
36 |         public LikenessException(string message, Exception innerException)
37 |             : base(message, innerException)
38 |         {
39 |         }
40 | 
41 | #if SYSTEM_RUNTIME_SERIALIZATION
42 |         /// 
43 |         /// Initializes a new instance of the  class.
44 |         /// 
45 |         /// 
46 |         /// The  that holds the
47 |         /// serialized object data about the exception being thrown.
48 |         /// 
49 |         /// 
50 |         /// The  that contains
51 |         /// contextual information about the source or destination.
52 |         /// 
53 |         /// 
54 |         /// The  parameter is null.
55 |         /// 
56 |         /// 
57 |         /// The class name is null or  is zero (0).
58 |         /// 
59 |         protected LikenessException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
60 |             : base(info, context)
61 |         {
62 |         }
63 | #endif
64 |     }
65 | }
66 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/LikenessMember.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Reflection;
 3 | 
 4 | namespace SemanticComparison
 5 | {
 6 |     /// 
 7 |     /// Encapsulates information about a member (property or field) which is used in a
 8 |     ///  comparison.
 9 |     /// 
10 |     /// The type of the source value.
11 |     /// 
12 |     /// The type of the destination that is evaluated against the source value.
13 |     /// 
14 |     public class LikenessMember
15 |     {
16 |         private readonly Likeness likeness;
17 |         private readonly MemberInfo member;
18 | 
19 |         internal LikenessMember(Likeness likeness, MemberInfo memberInfo)
20 |         {
21 |             if (likeness == null)
22 |             {
23 |                 throw new ArgumentNullException(nameof(likeness));
24 |             }
25 |             if (memberInfo == null)
26 |             {
27 |                 throw new ArgumentNullException(nameof(memberInfo));
28 |             }
29 | 
30 |             this.likeness = likeness;
31 |             this.member = memberInfo;
32 |         }
33 | 
34 |         /// 
35 |         /// Returns a new  that includes the specified
36 |         /// evaluator.
37 |         /// 
38 |         /// 
39 |         /// An expression that evaluates the source value against the destination value for the
40 |         /// property or field encapsulated by the instance.
41 |         /// 
42 |         /// A new  that includes
43 |         /// .
44 |         /// 
45 |         public Likeness EqualsWhen(Func evaluator)
46 |         {
47 |             var memberEvaluator = new MemberEvaluator(this.member, evaluator);
48 |             return this.likeness.AddEvaluator(memberEvaluator);
49 |         }
50 |     }
51 | }
52 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/MemberComparer.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Collections;
  3 | using System.Reflection;
  4 | 
  5 | namespace SemanticComparison
  6 | {
  7 |     /// 
  8 |     /// Provides custom equality comparison for requests of a property and field.
  9 |     /// 
 10 |     public class MemberComparer : IMemberComparer
 11 |     {
 12 |         /// 
 13 |         /// Initializes a new instance of the  
 14 |         /// class with the supplied  to support
 15 |         /// the comparison of properties and fields.
 16 |         /// 
 17 |         /// 
 18 |         /// The supplied .
 19 |         /// 
 20 |         public MemberComparer(IEqualityComparer comparer)
 21 |             : this(
 22 |                 comparer,
 23 |                 new TrueSpecification(),
 24 |                 new TrueSpecification())
 25 |         {
 26 |         }
 27 | 
 28 |         /// 
 29 |         /// Initializes a new instance of the 
 30 |         /// class with the supplied ,
 31 |         /// , and
 32 |         ///  to support the
 33 |         /// comparison of properties and fields.
 34 |         /// 
 35 |         /// 
 36 |         /// The supplied .
 37 |         /// 
 38 |         /// 
 39 |         /// The supplied Specification used to control whether or not a property
 40 |         /// should be compared.
 41 |         /// 
 42 |         /// 
 43 |         /// The supplied Specification used to control whether or not a field 
 44 |         /// should be compared.
 45 |         /// 
 46 |         public MemberComparer(
 47 |             IEqualityComparer comparer,
 48 |             ISpecification propertySpecification,
 49 |             ISpecification fieldSpecification)
 50 |         {
 51 |             if (comparer == null)
 52 |                 throw new ArgumentNullException(nameof(comparer));
 53 | 
 54 |             if (propertySpecification == null)
 55 |                 throw new ArgumentNullException(nameof(propertySpecification));
 56 | 
 57 |             if (fieldSpecification == null)
 58 |                 throw new ArgumentNullException(nameof(fieldSpecification));
 59 | 
 60 |             this.Comparer = comparer;
 61 |             this.PropertySpecification = propertySpecification;
 62 |             this.FieldSpecification = fieldSpecification;
 63 |         }
 64 | 
 65 |         /// 
 66 |         /// Gets the supplied .
 67 |         /// 
 68 |         /// 
 69 |         /// The supplied .
 70 |         /// 
 71 |         public IEqualityComparer Comparer { get; }
 72 | 
 73 |         /// 
 74 |         /// Gets the supplied Specification used to control whether or not a property
 75 |         /// should be compared.
 76 |         /// 
 77 |         /// 
 78 |         /// The supplied Specification used to control whether or not a property should
 79 |         /// be compared.
 80 |         /// 
 81 |         public ISpecification PropertySpecification { get; }
 82 | 
 83 |         /// 
 84 |         /// Gets the supplied Specification used to control whether or not a field
 85 |         /// should be compared.
 86 |         /// 
 87 |         /// 
 88 |         /// The supplied Specification used to control whether or not a field should
 89 |         /// be compared.
 90 |         /// 
 91 |         public ISpecification FieldSpecification { get; }
 92 | 
 93 |         /// 
 94 |         /// Evaluates a request for comparison of a property.
 95 |         /// 
 96 |         /// The request for comparison of a property.
 97 |         /// .
 98 |         public bool IsSatisfiedBy(PropertyInfo request)
 99 |         {
100 |             return this.PropertySpecification.IsSatisfiedBy(request);
101 |         }
102 | 
103 |         /// 
104 |         /// Evaluates a request for comparison of a field.
105 |         /// 
106 |         /// The request for comparison of a field.
107 |         /// .
108 |         public bool IsSatisfiedBy(FieldInfo request)
109 |         {
110 |             return this.FieldSpecification.IsSatisfiedBy(request);
111 |         }
112 | 
113 |         /// 
114 |         /// Determines whether the specified  is 
115 |         /// equal to this instance.
116 |         /// 
117 |         /// The  to compare with
118 |         /// this instance.
119 |         /// The y.
120 |         /// 
121 |         ///   true if the specified  
122 |         ///   is equal to this instance; otherwise, false.
123 |         /// 
124 |         /// 
125 |         ///   
126 |         ///      and  are considered
127 |         ///     equal if the supplied 's Equals 
128 |         ///     method returns .
129 |         ///   
130 |         /// 
131 |         public new bool Equals(object x, object y)
132 |         {
133 |             return this.Comparer.Equals(x, y);
134 |         }
135 | 
136 |         /// 
137 |         /// Returns a hash code for this instance.
138 |         /// 
139 |         /// The obj.
140 |         /// 
141 |         /// A hash code for this instance, suitable for use in hashing 
142 |         /// algorithms and data structures like a hash table. 
143 |         /// 
144 |         public int GetHashCode(object obj)
145 |         {
146 |             return this.Comparer.GetHashCode(obj);
147 |         }
148 |     }
149 | }
150 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/MemberEvaluator.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Reflection;
 3 | 
 4 | namespace SemanticComparison
 5 | {
 6 |     internal class MemberEvaluator
 7 |     {
 8 |         public MemberEvaluator(MemberInfo member, Func evaluator)
 9 |         {
10 |             if (member == null)
11 |             {
12 |                 throw new ArgumentNullException(nameof(member));
13 |             }
14 |             if (evaluator == null)
15 |             {
16 |                 throw new ArgumentNullException(nameof(evaluator));
17 |             }
18 | 
19 |             this.Member = member;
20 |             this.Evaluator = evaluator;
21 |         }
22 | 
23 |         internal Func Evaluator { get; }
24 | 
25 |         internal MemberInfo Member { get; }
26 |     }
27 | }
28 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/MemberInfoExtension.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Linq.Expressions;
 3 | using System.Reflection;
 4 | 
 5 | namespace SemanticComparison
 6 | {
 7 |     internal static class MemberInfoExtension
 8 |     {
 9 |         private readonly static MethodInfo equalsMember = typeof(object).GetTypeInfo().GetMethod("Equals", BindingFlags.Public | BindingFlags.Static);
10 | 
11 |         internal static MemberEvaluator ToEvaluator(this MemberInfo member)
12 |         {
13 |             var property = member as PropertyInfo;
14 |             if ((property != null) && (property.GetIndexParameters().Length > 0))
15 |             {
16 |                 return new MemberEvaluator(member, (TSource s, TDestination d) => true);
17 |             }
18 | 
19 |             var srcParam = Expression.Parameter(typeof(TSource), "x");
20 |             var destParam = Expression.Parameter(typeof(TDestination), "y");
21 | 
22 |             try
23 |             {
24 |                 var srcMember = Expression.PropertyOrField(srcParam, member.Name);
25 |                 var destMember = Expression.PropertyOrField(destParam, member.Name);
26 | 
27 |                 var eq = Expression.Equal(
28 |                     Expression.TypeAs(srcMember, typeof(object)),
29 |                     Expression.TypeAs(destMember, typeof(object)),
30 |                     false,
31 |                     MemberInfoExtension.equalsMember);
32 | 
33 |                 var exp = Expression.Lambda>(eq, srcParam, destParam);
34 |                 return new MemberEvaluator(member, exp.Compile());
35 |             }
36 |             catch (ArgumentException)
37 |             {
38 |                 return new MemberEvaluator(member, (TSource s, TDestination d) => false);
39 |             }
40 |             catch (AmbiguousMatchException)
41 |             {
42 |                 return new MemberEvaluator(member, (TSource s, TDestination d) => false);
43 |             }
44 |         }
45 | 
46 |         internal static Type ToUnderlyingType(this MemberInfo member)
47 |         {
48 |             switch (member.MemberType)
49 |             {
50 |                 case MemberTypes.Field:
51 |                     return ((FieldInfo)member).FieldType;
52 |                 case MemberTypes.Property:
53 |                     return ((PropertyInfo)member).PropertyType;
54 |                 default:
55 |                     throw new ArgumentException("MemberInfo must either FieldInfo or PropertyInfo.", nameof(member));
56 |             }
57 |         }
58 |     }
59 | }
60 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/MemberInfoNameComparer.cs:
--------------------------------------------------------------------------------
 1 | using System.Collections.Generic;
 2 | using System.Reflection;
 3 | 
 4 | namespace SemanticComparison
 5 | {
 6 |     /// 
 7 |     /// Compares  instances.
 8 |     /// 
 9 |     public class MemberInfoNameComparer : IEqualityComparer
10 |     {
11 |         /// 
12 |         /// Compares two  instances for equality.
13 |         /// 
14 |         /// The first instance to compare.
15 |         /// The second instance to compare.
16 |         /// 
17 |         ///  if  and  has the same
18 |         /// name; otherwise, .
19 |         /// 
20 |         public bool Equals(MemberInfo x, MemberInfo y)
21 |         {
22 |             return ((x == y) || (((x != null) && (y != null)) && object.Equals(x.Name, y.Name)));
23 |         }
24 | 
25 |         /// 
26 |         /// Returns the hash code of the  instance's
27 |         /// .
28 |         /// 
29 |         /// The  for which to return a hash code.
30 |         /// 
31 |         /// The hash code of the  instance's .
32 |         /// 
33 |         public int GetHashCode(MemberInfo obj)
34 |         {
35 |             if (obj == null) return 0;
36 | 
37 |             return obj.Name.GetHashCode();
38 |         }
39 |     }
40 | }
41 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.InteropServices;
 3 | using System;
 4 | using System.Resources;
 5 | 
 6 | // General Information about an assembly is controlled through the following 
 7 | // set of attributes. Change these attribute values to modify the information
 8 | // associated with an assembly.
 9 | [assembly: AssemblyCulture("")]
10 | 
11 | // Setting ComVisible to false makes the types in this assembly not visible 
12 | // to COM components.  If you need to access a type in this assembly from 
13 | // COM, set the ComVisible attribute to true on that type.
14 | [assembly: ComVisible(false)]
15 | 
16 | // The following GUID is for the ID of the typelib if this project is exposed to COM
17 | [assembly: Guid("aa10d66a-ba01-496a-a601-26adbd228ad2")]
18 | 
19 | [assembly: CLSCompliant(true)]
20 | [assembly: NeutralResourcesLanguageAttribute("en")]
21 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/ProxyCreationException.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparison
 4 | {
 5 |     /// 
 6 |     /// Represents an error during the dynamic proxy creation.
 7 |     /// 
 8 | #if SYSTEM_RUNTIME_SERIALIZATION
 9 |     [Serializable]
10 | #endif
11 |     public class ProxyCreationException : Exception
12 |     {
13 |         /// 
14 |         /// Initializes a new instance of the  class.
15 |         /// 
16 |         public ProxyCreationException()
17 |         {
18 |         }
19 | 
20 |         /// 
21 |         /// Initializes a new instance of the  class.
22 |         /// 
23 |         /// The message.
24 |         public ProxyCreationException(string message)
25 |             : base(message)
26 |         {
27 |         }
28 | 
29 |         /// 
30 |         /// Initializes a new instance of the  class.
31 |         /// 
32 |         /// The message.
33 |         /// The inner exception.
34 |         public ProxyCreationException(string message, Exception innerException)
35 |             : base(message, innerException)
36 |         {
37 |         }
38 | 
39 | #if SYSTEM_RUNTIME_SERIALIZATION
40 |         /// 
41 |         /// Initializes a new instance of the  class.
42 |         /// 
43 |         /// 
44 |         /// The  that holds the
45 |         /// serialized object data about the exception being thrown.
46 |         /// 
47 |         /// 
48 |         /// The  that contains
49 |         /// contextual information about the source or destination.
50 |         /// 
51 |         /// 
52 |         /// The  parameter is null.
53 |         /// 
54 |         /// 
55 |         /// The class name is null or  is zero (0).
56 |         /// 
57 |         protected ProxyCreationException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
58 |             : base(info, context)
59 |         {
60 |         }
61 | #endif
62 |     }
63 | }


--------------------------------------------------------------------------------
/Src/SemanticComparison/ProxyGenerator.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Collections;
  3 | using System.Collections.Generic;
  4 | using System.Linq;
  5 | using System.Reflection;
  6 | using System.Reflection.Emit;
  7 | 
  8 | namespace SemanticComparison
  9 | {
 10 |     internal static class ProxyGenerator
 11 |     {
 12 |         private const string assemblyName = "SemanticComparisonGeneratedAssembly";
 13 | 
 14 |         internal static TDestination CreateLikenessProxy(TSource source, IEqualityComparer comparer, IEnumerable members)
 15 |         {
 16 |             ProxyType proxyType = ProxyGenerator.FindCompatibleConstructor(source, members.ToArray());
 17 |             TypeBuilder builder = ProxyGenerator.BuildType(BuildModule(BuildAssembly(assemblyName)));
 18 |             FieldBuilder equals = ProxyGenerator.BuildFieldComparer(builder, comparer.GetType());
 19 | 
 20 |             ProxyGenerator.BuildConstructors(proxyType.Constructor, builder, equals);
 21 |             ProxyGenerator.BuildMethodEquals(builder, BuildFieldEqualsHasBeenCalled(builder), equals);
 22 |             ProxyGenerator.BuildMethodGetHashCode(builder);
 23 | 
 24 |             var destination = (TDestination)Activator.CreateInstance(
 25 |                 builder.CreateTypeInfo().AsType(), 
 26 |                 proxyType.Parameters.Concat(new[] { comparer }).ToArray());
 27 | 
 28 |             ProxyGenerator.Map(source, destination);
 29 | 
 30 |             return destination;
 31 |         }
 32 | 
 33 |         internal static T CreateLikenessResemblance(Likeness likeness)
 34 |         {
 35 |             var members = typeof(T)
 36 |                 .GetTypeInfo()
 37 |                 .GetProperties(BindingFlags.Public | BindingFlags.Instance)
 38 |                 .Concat(typeof(T)
 39 |                     .GetTypeInfo()
 40 |                     .GetFields(BindingFlags.Public | BindingFlags.Instance)
 41 |                     .Cast())
 42 |                 .ToArray();
 43 | 
 44 |             ProxyType proxyType = 
 45 |                 ProxyGenerator.FindCompatibleConstructor(
 46 |                     likeness.Value,
 47 |                     members);
 48 | 
 49 |             TypeBuilder builder = 
 50 |                 ProxyGenerator.BuildType(
 51 |                     ProxyGenerator.BuildModule(
 52 |                         ProxyGenerator.BuildAssembly(assemblyName)));
 53 | 
 54 |             FieldBuilder equals =
 55 |                 ProxyGenerator.BuildFieldComparer(builder, likeness.GetType());
 56 | 
 57 |             ProxyGenerator.BuildConstructors(
 58 |                 proxyType.Constructor, 
 59 |                 builder,
 60 |                 equals);
 61 | 
 62 |             ProxyGenerator.BuildMethodEquals(builder, equals);
 63 |             ProxyGenerator.BuildMethodGetHashCode(builder);
 64 | 
 65 |             return (T)Activator.CreateInstance(
 66 |                 builder.CreateTypeInfo().AsType(),
 67 |                 proxyType.Parameters.Concat(
 68 |                     new[] { likeness }).ToArray());
 69 |         }
 70 | 
 71 |         private static AssemblyBuilder BuildAssembly(string name)
 72 |         {
 73 |             var an = new AssemblyName(name) { Version = typeof(ProxyGenerator).GetTypeInfo().Assembly.GetName().Version };
 74 | 
 75 | #if SYSTEM_REFLECTION_EMIT_DYNAMICASSEMBLY_SAVE
 76 |             var access = AssemblyBuilderAccess.RunAndSave;
 77 | #else
 78 |             var access = AssemblyBuilderAccess.Run;
 79 | #endif
 80 |             return AssemblyBuilder.DefineDynamicAssembly(an, access);
 81 |         }
 82 | 
 83 |         private static ModuleBuilder BuildModule(AssemblyBuilder ab)
 84 |         {
 85 | #if SYSTEM_REFLECTION_EMIT_DYNAMICASSEMBLY_SAVE
 86 |             return ab.DefineDynamicModule(assemblyName, assemblyName + ".dll");
 87 | #else
 88 |             return ab.DefineDynamicModule(assemblyName);
 89 | #endif
 90 |         }
 91 | 
 92 |         private static TypeBuilder BuildType(ModuleBuilder mb)
 93 |         {
 94 |             TypeBuilder type = mb.DefineType(
 95 |                 typeof(TDestination).Name + "Proxy" + Guid.NewGuid().ToString().Replace("-", ""),
 96 |                 TypeAttributes.NotPublic,
 97 |                 typeof(TDestination));
 98 |             return type;
 99 |         }
100 | 
101 |         private static FieldBuilder BuildFieldEqualsHasBeenCalled(TypeBuilder type)
102 |         {
103 |             FieldBuilder field = type.DefineField(
104 |                 "equalsHasBeenCalled",
105 |                 typeof(bool),
106 |                   FieldAttributes.Private
107 |                 );
108 |             return field;
109 |         }
110 | 
111 |         private static FieldBuilder BuildFieldComparer(
112 |             TypeBuilder type, 
113 |             Type comparerType)
114 |         {
115 |             FieldBuilder field = type.DefineField(
116 |                 "comparer",
117 |                 comparerType,
118 |                 FieldAttributes.Private | FieldAttributes.InitOnly);
119 |             return field;
120 |         }
121 | 
122 |         private static void BuildConstructors(ConstructorInfo ci, TypeBuilder type, FieldInfo comparer)
123 |         {
124 |             Type[] constructorParameterTypes = BuildConstructorParameterTypes(ci, comparer.FieldType).ToArray();
125 | 
126 |             ConstructorBuilder constructor = type.DefineConstructor(
127 |                 MethodAttributes.Public | MethodAttributes.HideBySig,
128 |                 CallingConventions.Standard,
129 |                 constructorParameterTypes);
130 | 
131 |             for (int position = 1; position <= constructorParameterTypes.Length; position++)
132 |             {
133 |                 constructor.DefineParameter(position, ParameterAttributes.None, "arg" + position);
134 |             }
135 | 
136 |             ILGenerator gen = constructor.GetILGenerator();
137 | 
138 |             for (int position = 0; position < constructorParameterTypes.Length; position++)
139 |             {
140 |                 if (position == 0)
141 |                 {
142 |                     gen.Emit(OpCodes.Ldarg_0);
143 |                 }
144 |                 else if (position == 1)
145 |                 {
146 |                     gen.Emit(OpCodes.Ldarg_1);
147 |                 }
148 |                 else if (position == 2)
149 |                 {
150 |                     gen.Emit(OpCodes.Ldarg_2);
151 |                 }
152 |                 else if (position == 3)
153 |                 {
154 |                     gen.Emit(OpCodes.Ldarg_3);
155 |                 }
156 |                 else
157 |                 {
158 |                     gen.Emit(OpCodes.Ldarg_S, position);
159 |                 }
160 |             }
161 | 
162 |             gen.Emit(OpCodes.Call, ci);
163 |             gen.Emit(OpCodes.Nop);
164 |             gen.Emit(OpCodes.Nop);
165 |             gen.Emit(OpCodes.Ldarg_0);
166 |             gen.Emit(OpCodes.Ldarg_S, constructorParameterTypes.Length);
167 |             gen.Emit(OpCodes.Stfld, comparer);
168 |             gen.Emit(OpCodes.Nop);
169 |             gen.Emit(OpCodes.Ret);
170 |         }
171 | 
172 |         private static IEnumerable BuildConstructorParameterTypes(ConstructorInfo baseConstructor, Type comparerType)
173 |         {
174 |             return (from pi in baseConstructor.GetParameters()
175 |                     select pi.ParameterType)
176 |                     .Concat(new[] { comparerType });
177 |         }
178 | 
179 |         private static void BuildMethodGetHashCode(TypeBuilder type)
180 |         {
181 |             var methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
182 |             MethodBuilder method = type.DefineMethod("GetHashCode", methodAttributes);
183 |             method.SetReturnType(typeof(int));
184 | 
185 |             int derivedGetHashCode = 135;
186 |             MethodInfo getHashCode = typeof(TDestination).GetTypeInfo().GetMethod(
187 |                 "GetHashCode",
188 |                 Type.EmptyTypes
189 |             );
190 | 
191 |             ILGenerator gen = method.GetILGenerator();
192 |             gen.DeclareLocal(typeof(int));
193 |             
194 |             Label label = gen.DefineLabel();
195 |             
196 |             gen.Emit(OpCodes.Nop);
197 |             gen.Emit(OpCodes.Ldarg_0);
198 |             gen.Emit(OpCodes.Call, getHashCode);
199 |             gen.Emit(OpCodes.Ldc_I4, derivedGetHashCode);
200 |             gen.Emit(OpCodes.Add);
201 |             gen.Emit(OpCodes.Stloc_0);
202 |             gen.Emit(OpCodes.Br_S, label);
203 |             gen.MarkLabel(label);
204 |             gen.Emit(OpCodes.Ldloc_0);
205 |             gen.Emit(OpCodes.Ret);
206 |         }
207 | 
208 |         private static void BuildMethodEquals(TypeBuilder type, FieldInfo equalsHasBeenCalled, FieldInfo comparer)
209 |         {
210 |             var methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
211 |             MethodBuilder method = type.DefineMethod("Equals", methodAttributes);
212 | 
213 |             MethodInfo objectEquals = typeof(object).GetTypeInfo().GetMethod(
214 |                 "Equals",
215 |                 new[] {typeof(object)}
216 |             );
217 | 
218 |             MethodInfo equalityComparerEquals = typeof(IEqualityComparer).GetTypeInfo().GetMethod(
219 |                 "Equals",
220 |                 new[] {typeof(object), typeof(object)}
221 |             );
222 |             
223 |             method.SetReturnType(typeof(bool));
224 |             method.SetParameters(typeof(object));
225 |             method.DefineParameter(1, ParameterAttributes.None, "obj");
226 |             
227 |             ILGenerator gen = method.GetILGenerator();
228 |             gen.DeclareLocal(typeof(bool));
229 |             gen.DeclareLocal(typeof(bool));
230 |             
231 |             Label label1 = gen.DefineLabel();
232 |             Label label2 = gen.DefineLabel();
233 | 
234 |             gen.Emit(OpCodes.Nop);
235 |             gen.Emit(OpCodes.Ldarg_0);
236 |             gen.Emit(OpCodes.Ldfld, equalsHasBeenCalled);
237 |             gen.Emit(OpCodes.Ldc_I4_0);
238 |             gen.Emit(OpCodes.Ceq);
239 |             gen.Emit(OpCodes.Stloc_1);
240 |             gen.Emit(OpCodes.Ldloc_1);
241 |             gen.Emit(OpCodes.Brtrue_S, label1);
242 |             gen.Emit(OpCodes.Nop);
243 |             gen.Emit(OpCodes.Ldarg_0);
244 |             gen.Emit(OpCodes.Ldc_I4_0);
245 |             gen.Emit(OpCodes.Stfld, equalsHasBeenCalled);
246 |             gen.Emit(OpCodes.Ldarg_0);
247 |             gen.Emit(OpCodes.Ldarg_1);
248 |             gen.Emit(OpCodes.Call, objectEquals);
249 |             gen.Emit(OpCodes.Stloc_0);
250 |             gen.Emit(OpCodes.Br_S, label2);
251 |             gen.MarkLabel(label1);
252 |             gen.Emit(OpCodes.Ldarg_0);
253 |             gen.Emit(OpCodes.Ldc_I4_1);
254 |             gen.Emit(OpCodes.Stfld, equalsHasBeenCalled);
255 |             gen.Emit(OpCodes.Ldarg_0);
256 |             gen.Emit(OpCodes.Ldfld, comparer);
257 |             gen.Emit(OpCodes.Ldarg_0);
258 |             gen.Emit(OpCodes.Ldarg_1);
259 |             gen.Emit(OpCodes.Callvirt, equalityComparerEquals);
260 |             gen.Emit(OpCodes.Stloc_0);
261 |             gen.Emit(OpCodes.Br_S, label2);
262 |             gen.MarkLabel(label2);
263 |             gen.Emit(OpCodes.Ldloc_0);
264 |             gen.Emit(OpCodes.Ret);
265 |         }
266 | 
267 |         private static void BuildMethodEquals(TypeBuilder type, FieldInfo comparer)
268 |         {
269 |             var methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
270 |             MethodBuilder method = type.DefineMethod("Equals", methodAttributes);
271 | 
272 |             MethodInfo equals = typeof(object).GetTypeInfo().GetMethod(
273 |                 "Equals",
274 |                 new[] {typeof(object)}
275 |             );
276 | 
277 |             method.SetReturnType(typeof(bool));
278 |             method.SetParameters(typeof(object));
279 | 
280 |             ILGenerator gen = method.GetILGenerator();
281 |             gen.DeclareLocal(typeof(bool));
282 | 
283 |             var label = gen.DefineLabel();
284 | 
285 |             gen.Emit(OpCodes.Nop);
286 |             gen.Emit(OpCodes.Ldarg_0);
287 |             gen.Emit(OpCodes.Ldfld, comparer);
288 |             gen.Emit(OpCodes.Ldarg_1);
289 |             gen.Emit(OpCodes.Callvirt, equals);
290 |             gen.Emit(OpCodes.Stloc_0);
291 |             gen.Emit(OpCodes.Br_S, label);
292 |             gen.MarkLabel(label);
293 |             gen.Emit(OpCodes.Ldloc_0);
294 |             gen.Emit(OpCodes.Ret);
295 |         }
296 | 
297 |         private static ProxyType FindCompatibleConstructor(
298 |             object source,
299 |             MemberInfo[] members)
300 |         {
301 |             IEnumerable constructors = typeof(TDestination)
302 |                 .GetPublicAndProtectedConstructors();
303 |            
304 |             foreach (ConstructorInfo constructor in constructors)
305 |             {
306 |                 List parameterTypes =
307 |                     constructor.GetParameterTypes().ToList();
308 | 
309 |                 var parameters = members.GetParameters(source, parameterTypes).ToArray();
310 | 
311 |                 var parameterValues = parameters.Select(a => a.Value).ToArray();
312 | 
313 |                 if (!parameters.Any())
314 |                     return new ProxyType(constructor);
315 | 
316 |                 foreach (var parameter in parameters)                
317 |                     if (parameterTypes.Any(x => x == parameter.Type))
318 |                         return new ProxyType(constructor, parameterValues);              
319 |             }
320 | 
321 |             throw new InvalidOperationException();
322 |         }
323 | 
324 |         private static IEnumerable GetPublicAndProtectedConstructors(
325 |             this Type type)
326 |         {
327 |             return type.GetTypeInfo().GetConstructors(
328 |                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(x => x.IsPublic || x.IsFamily);
329 |         }
330 | 
331 |         private static IEnumerable GetParameterTypes(
332 |             this ConstructorInfo ci)
333 |         {
334 |             return ci.GetParameters().Select(pi => pi.ParameterType);
335 |         }
336 | 
337 |       
338 |        private static IEnumerable GetParameters(
339 |           this IEnumerable members,
340 |           object source,
341 |           List parameterTypes)
342 |        {
343 |            List parameters = members
344 |                .Where(mi => parameterTypes.Matches(mi.ToUnderlyingType()))
345 |                .Select(x => source.GetType()
346 |                    .MatchProperty(x.Name).GetValue(source, null))
347 |                .Take(parameterTypes.Count())
348 |                .ToList();
349 | 
350 |            var sourceMap = source.GetSourceTypeValuePairs();
351 | 
352 |            return (!sourceMap.AreOrderedBy(parameterTypes)) ? 
353 |                 sourceMap.OrderByType(parameterTypes)
354 |                    :  sourceMap;
355 |                       
356 |        }     
357 | 
358 |         private static bool Matches(this List types, Type type)
359 |         {
360 |             var typeInfo = type.GetTypeInfo();
361 | 
362 |             return types.Contains(type)
363 |                 || types.Select(t => t.GetTypeInfo()).Any(t => t.IsAssignableFrom(typeInfo)
364 |                     || typeInfo.IsAssignableFrom(t));
365 |         }
366 | 
367 |         private static PropertyInfo MatchProperty(this Type type, string name)
368 |         {
369 |             return type.GetTypeInfo().GetProperty(name) ?? type.FindCompatibleProperty(name);
370 |         }
371 | 
372 |         private static PropertyInfo FindCompatibleProperty(this Type type, 
373 |             string name)
374 |         {
375 |             return type.GetTypeInfo().GetProperties(
376 |                     BindingFlags.Public | BindingFlags.Instance)
377 |                        .First(x => x.Name.StartsWith(
378 |                             name, StringComparison.OrdinalIgnoreCase));
379 |         }
380 | 
381 |        
382 |         private static IEnumerable GetSourceTypeValuePairs(this object source)
383 |         {
384 |             return source.GetType()
385 |                     .GetTypeInfo()
386 |                     .GetProperties(BindingFlags.Public | BindingFlags.Instance)
387 |                     .Select(a => new SourceTypeValuePair(a.PropertyType, a.GetValue(source, null)));            
388 |         }       
389 |       
390 |         private static bool AreOrderedBy(this IEnumerable sourceMap, IEnumerable types)
391 |         {
392 |             return sourceMap.Select(a => a.Type.Name).SequenceEqual(types.Select(b => b.Name));
393 |         }
394 | 
395 |         private static IEnumerable OrderByType(
396 |          this IEnumerable sequence,
397 |          IEnumerable types)
398 |         {
399 |             return from t in types
400 |                    select sequence.First(x => x.Type.GetTypeInfo().IsAssignableFrom(t));
401 |         }
402 | 
403 | 
404 |         private static void Map(object source, object target)
405 |         {
406 |             ISet sourceFields = source.GetType().FindAllFields();
407 |             ISet targetFields = target.GetType().GetTypeInfo().BaseType.FindAllFields();
408 | 
409 |             var matchedTargetFields =
410 |                 (from s in sourceFields
411 |                  from t in targetFields
412 |                  where s.Match(t)
413 |                  select t)
414 |                  .ToArray();
415 | 
416 |             foreach (FieldInfo fi in matchedTargetFields)
417 |             {
418 |                 var sourceField = sourceFields
419 |                     .Where(s => s.Name.Equals(fi.Name, StringComparison.Ordinal))
420 |                         .Concat(sourceFields
421 |                             .Where(s => s.Match(fi)))
422 |                     .FirstOrDefault();
423 |                 if (sourceField != null)
424 |                     fi.SetValue(
425 |                         target,
426 |                         sourceField.GetValue(source));
427 |             }
428 |         }
429 | 
430 |         private static ISet FindAllFields(this Type t)
431 |         {
432 |             var allFields = new HashSet();
433 |             
434 |             Type type = t;
435 |             while (type != null)
436 |             {
437 |                 var fields =
438 |                     type.GetTypeInfo().GetFields(
439 |                         BindingFlags.Public |
440 |                         BindingFlags.Instance |
441 |                         BindingFlags.NonPublic);
442 | 
443 |                 foreach (FieldInfo field in fields)
444 |                     if (!allFields.Contains(field))
445 |                         allFields.Add(field);
446 | 
447 |                 type = type.GetTypeInfo().BaseType;
448 |             }
449 | 
450 |             return allFields;
451 |         }
452 | 
453 |         private static bool Match(this FieldInfo source, FieldInfo target)
454 |         {
455 |             var sourceName = ProxyGenerator
456 |                 .TrimCompilerGeneratedText(source.Name)
457 |                 .ToUpperInvariant();
458 |             
459 |             var targetName = ProxyGenerator
460 |                 .TrimCompilerGeneratedText(target.Name)
461 |                 .ToUpperInvariant();
462 | 
463 |             return (sourceName.Contains(targetName)
464 |                  || targetName.Contains(sourceName))
465 |                  && source.FieldType == target.FieldType;
466 |         }
467 | 
468 |         private static string TrimCompilerGeneratedText(string s)
469 |         {
470 |             return s
471 |                 .Replace("i__Field", null)
472 |                 .Replace("<", null)
473 |                 .Replace(">", null)
474 |                 .Replace("k__BackingField", null);
475 |         }
476 | 
477 |         private class SourceTypeValuePair
478 |         {
479 |             public SourceTypeValuePair(Type type, object value)
480 |             {
481 |                 if (type == null)
482 |                     throw new ArgumentNullException(nameof(type));
483 | 
484 |                 this.Type = type;
485 |                 this.Value = value;
486 |             }
487 | 
488 |             [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1721:Property names should not match get methods", Justification = "It's fine to have the 'Type' property and we cannot re-use the GetType() method intead.")]
489 |             public Type Type { get; }
490 |             public object Value { get; }
491 |         }
492 |     }
493 | }
494 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/ProxyType.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Collections.Generic;
 3 | using System.Reflection;
 4 | 
 5 | namespace SemanticComparison
 6 | {
 7 |     internal class ProxyType
 8 |     {
 9 |         internal ProxyType(
10 |             ConstructorInfo constructor,
11 |             params object[] parameters)
12 |         {
13 |             if (constructor == null)
14 |                 throw new ArgumentNullException(nameof(constructor));
15 | 
16 |             if (parameters == null)
17 |                 throw new ArgumentNullException(nameof(parameters));
18 | 
19 |             this.Constructor = constructor;
20 |             this.Parameters = parameters;
21 |         }
22 | 
23 |         internal ConstructorInfo Constructor { get; }
24 | 
25 |         internal IEnumerable Parameters { get; }
26 |     }
27 | }
28 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/SemanticComparer.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Collections;
  3 | using System.Collections.Generic;
  4 | using System.Linq;
  5 | using System.Reflection;
  6 | 
  7 | namespace SemanticComparison
  8 | {
  9 |     /// 
 10 |     /// Provides a class with implementations of the System.Collections.Generic.IEqualityComparer{T}
 11 |     /// and System.Collections.Generic.IEqualityComparer interfaces for convention-based object 
 12 |     /// equality comparison for use when comparing two semantically equivalent, but different, objects.
 13 |     /// 
 14 |     /// The type of the source value (against which the destination value 
 15 |     /// will be compared for equality).
 16 |     /// The type of the destination value which will be compared for 
 17 |     /// equality against the source value.
 18 |     public class SemanticComparer : IEqualityComparer, IEqualityComparer
 19 |     {
 20 |         /// 
 21 |         /// Initializes a new instance of the  class.
 22 |         /// 
 23 |         public SemanticComparer()
 24 |             :this(Enumerable.Empty>(), DefaultMembers.Generate)
 25 |         {
 26 |         }
 27 | 
 28 |         internal SemanticComparer(IEnumerable> evaluators, Func> defaultMembersGenerator)
 29 |         {
 30 |             this.Evaluators = evaluators;
 31 |             this.DefaultMembersGenerator = defaultMembersGenerator;
 32 |         }
 33 | 
 34 |         internal IEnumerable> Evaluators { get; }
 35 | 
 36 |         internal Func> DefaultMembersGenerator { get; }
 37 | 
 38 |         /// 
 39 |         /// Determines whether the specified  is equal to this instance.
 40 |         /// 
 41 |         /// The source value (against which the destination value will be compared for
 42 |         /// equality).
 43 |         /// The destination value which will be compared for equality against the 
 44 |         /// source value.
 45 |         /// 
 46 |         ///   true if the specified  is equal to this instance; 
 47 |         ///   otherwise, false.
 48 |         /// 
 49 |         public new bool Equals(object x, object y)
 50 |         {
 51 |             if ((x == null) && (y == null))
 52 |             {
 53 |                 return true;
 54 |             }
 55 | 
 56 |             if (x == null)
 57 |             {
 58 |                 return false;
 59 |             }
 60 | 
 61 |             if (y == null)
 62 |             {
 63 |                 return false;
 64 |             }
 65 | 
 66 |             if (x.Equals(y))
 67 |             {
 68 |                 return true;
 69 |             }
 70 | 
 71 |             if (x is TSource && y is TDestination)
 72 |             {
 73 |                 return this.GetEvaluators().All(me => me.Evaluator((TSource)x, (TDestination)y));
 74 |             }
 75 | 
 76 |             if (x is TDestination && y is TSource)
 77 |             {
 78 |                 return this.GetEvaluators().All(me => me.Evaluator((TSource)y, (TDestination)x));
 79 |             }
 80 | 
 81 |             return false;
 82 |         }
 83 | 
 84 |         /// 
 85 |         /// Returns a hash code for this instance.
 86 |         /// 
 87 |         /// The obj.
 88 |         /// 
 89 |         /// A hash code for this instance, suitable for use in hashing algorithms and data structures 
 90 |         /// like a hash table. 
 91 |         /// 
 92 |         /// 
 93 |         /// The type of  is a reference type and  is null.
 94 |         ///   
 95 |         public int GetHashCode(object obj)
 96 |         {
 97 |             return obj == null ? 0 : obj.GetHashCode();
 98 |         }
 99 | 
100 |         /// 
101 |         /// Determines whether the specified  is equal to this instance.
102 |         /// 
103 |         /// The source value (against which the destination value will be compared for
104 |         /// equality).
105 |         /// The destination value which will be compared for equality against the 
106 |         /// source value.
107 |         /// 
108 |         ///   true if the specified  is equal to this instance; 
109 |         ///   otherwise, false.
110 |         /// 
111 |         bool IEqualityComparer.Equals(object x, object y)
112 |         {
113 |             return this.Equals(x, y);
114 |         }
115 | 
116 |         /// 
117 |         /// Returns a hash code for this instance.
118 |         /// 
119 |         /// The obj.
120 |         /// 
121 |         /// A hash code for this instance, suitable for use in hashing algorithms and data structures 
122 |         /// like a hash table. 
123 |         /// 
124 |         /// 
125 |         /// The type of  is a reference type and  is null.
126 |         ///   
127 |         int IEqualityComparer.GetHashCode(object obj)
128 |         {
129 |             return this.GetHashCode(obj);
130 |         }
131 | 
132 |         internal IEnumerable> GetEvaluators()
133 |         {
134 |             var defaultMembers = this.DefaultMembersGenerator();
135 |             var undefinedMembers = defaultMembers.Except(this.Evaluators.Select(e => e.Member), new MemberInfoNameComparer());
136 |             var undefinedEvaluators = from mi in undefinedMembers
137 |                                       select mi.ToEvaluator();
138 |             return this.Evaluators.Concat(undefinedEvaluators);
139 |         }
140 | 
141 |         internal static class DefaultMembers
142 |         {
143 |             internal static IEnumerable Generate()
144 |             {
145 |                 return typeof(T)
146 |                     .GetTypeInfo()
147 |                     .GetProperties(BindingFlags.Public | BindingFlags.Instance)
148 |                     .Concat(typeof(T)
149 |                         .GetTypeInfo()
150 |                         .GetFields(BindingFlags.Public | BindingFlags.Instance)
151 |                         .Cast());
152 |             }
153 |         }
154 |     }
155 | 
156 |     /// 
157 |     /// Provides a class which implements the 
158 |     /// interface for convention-based object equality comparison for use when 
159 |     /// comparing two semantically equivalent objects.
160 |     /// 
161 |     /// 
162 |     /// The type of the value which will be compared for equality.
163 |     /// 
164 |     /// 
165 |     /// This class is a boolean 'And' Composite over 
166 |     /// instances.
167 |     /// 
168 |     public class SemanticComparer : IEqualityComparer, IEqualityComparer
169 |     {
170 |         /// 
171 |         /// Initializes a new instance of the 
172 |         /// class.
173 |         /// 
174 |         public SemanticComparer()
175 |             : this(new MemberComparer(new SemanticComparer()))
176 |         {
177 |         }
178 | 
179 |         /// 
180 |         /// Initializes a new instance of the 
181 |         /// class.
182 |         /// 
183 |         /// 
184 |         /// The supplied  instances.
185 |         /// 
186 |         /// 
187 |         /// comparers is null
188 |         /// 
189 |         public SemanticComparer(IEnumerable comparers)
190 |             : this(comparers.ToArray())
191 |         {
192 |         }
193 | 
194 |         /// 
195 |         /// Initializes a new instance of the 
196 |         /// class.
197 |         /// 
198 |         /// 
199 |         /// The supplied array of  instances.
200 |         /// 
201 |         /// 
202 |         /// comparers is null
203 |         /// 
204 |         public SemanticComparer(params IMemberComparer[] comparers)
205 |         {
206 |             if (comparers == null)
207 |                 throw new ArgumentNullException(nameof(comparers));
208 | 
209 |             this.Comparers = comparers;
210 |         }
211 | 
212 |         /// 
213 |         /// Gets the supplied  
214 |         /// instances.
215 |         /// 
216 |         /// 
217 |         /// The supplied 
218 |         /// instances.
219 |         /// 
220 |         public IEnumerable Comparers { get; }
221 | 
222 |         /// 
223 |         /// Determines whether the specified objects are equal.
224 |         /// 
225 |         /// The first object to compare.
226 |         /// The second object to compare.
227 |         /// 
228 |         /// true if the specified objects are equal; otherwise, false.
229 |         /// 
230 |         public bool Equals(T x, T y)
231 |         {
232 |             if (x == null && y == null)
233 |                 return true;
234 | 
235 |             if (x == null || y == null)
236 |                 return false;
237 | 
238 |             if (x.Equals(y))
239 |                 return true;
240 | 
241 |             var bindingAttributes = BindingFlags.Public | BindingFlags.Instance;
242 |             return typeof(T)
243 |                 .GetTypeInfo()
244 |                 .GetProperties(bindingAttributes)
245 |                 .Select(property => this.Comparers
246 |                     .Where(c => c.IsSatisfiedBy(property))
247 |                     .Any(c => c.Equals(
248 |                         property.GetValue(x, null),
249 |                         property.GetValue(y, null))))
250 |                 .Concat(typeof(T)
251 |                     .GetTypeInfo()
252 |                     .GetFields(bindingAttributes)
253 |                     .Select(field => this.Comparers
254 |                         .Where(c => c.IsSatisfiedBy(field))
255 |                         .Any(c => c.Equals(
256 |                             field.GetValue(x),
257 |                             field.GetValue(y)))))
258 |                 .All(equals => equals);
259 |         }
260 | 
261 |         /// 
262 |         /// Returns a hash code for this instance.
263 |         /// 
264 |         /// The obj.
265 |         /// 
266 |         /// A hash code for this instance, suitable for use in hashing 
267 |         /// algorithms and data structures like a hash table. 
268 |         /// 
269 |         public int GetHashCode(T obj)
270 |         {
271 |             return 0;
272 |         }
273 | 
274 |         /// 
275 |         /// Determines whether the specified objects are equal.
276 |         /// 
277 |         /// The first object to compare.
278 |         /// The second object to compare.
279 |         /// 
280 |         /// true if the specified objects are equal; otherwise, false.
281 |         /// 
282 |         bool IEqualityComparer.Equals(object x, object y)
283 |         {
284 |             if (x == null && y == null)
285 |                 return true;
286 | 
287 |             return (x is T && y is T) ? this.Equals((T)x, (T)y) : false;
288 |         }
289 | 
290 |         /// 
291 |         /// Returns a hash code for this instance.
292 |         /// 
293 |         /// The obj.
294 |         /// 
295 |         /// A hash code for this instance, suitable for use in hashing
296 |         /// algorithms and data structures like a hash table. 
297 |         /// 
298 |         int IEqualityComparer.GetHashCode(object obj)
299 |         {
300 |             return 0;
301 |         }
302 |     }
303 | }


--------------------------------------------------------------------------------
/Src/SemanticComparison/SemanticComparison.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 |   
 3 | 
 4 |   
 5 |     net452;netstandard1.5;netstandard2.0
 6 |     SemanticComparison
 7 |     SemanticComparison
 8 |     Copyright © Ploeh 2011
 9 | 
10 |     
11 |     SemanticComparison
12 |     SemanticComparison
13 |     SemanticComparison makes it easier to compare instances of various objects to each other. Instead of performing a normal equality comparison, SemanticComparison compares objects that look semantically similar - even if they are of different types. Various fine-tuning options exist.
14 |   
15 | 
16 |   
17 |     
18 |   
19 | 


--------------------------------------------------------------------------------
/Src/SemanticComparison/TrueSpecification.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparison
 2 | {
 3 |     /// 
 4 |     /// A  that is always .
 5 |     /// 
 6 |     public class TrueSpecification : ISpecification
 7 |     {
 8 |         /// 
 9 |         /// Determines whether a candidate is satisfied by the Specification.
10 |         /// 
11 |         /// The candidate.
12 |         /// 
13 |         public bool IsSatisfiedBy(T candidate)
14 |         {
15 |             return true;
16 |         }
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/DelegatingEqualityComparer.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Collections;
 3 | using System.Collections.Generic;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     internal class DelegatingEqualityComparer : IEqualityComparer
 8 |     {
 9 |         internal DelegatingEqualityComparer()
10 |         {
11 |             this.OnEquals = (x, y) => false;
12 |             this.OnGetHashCode = x => 0;
13 |         }
14 | 
15 |         bool IEqualityComparer.Equals(object x, object y)
16 |         {
17 |             return this.OnEquals(x, y);
18 |         }
19 | 
20 |         int IEqualityComparer.GetHashCode(object obj)
21 |         {
22 |             return this.OnGetHashCode(obj);
23 |         }
24 | 
25 |         internal Func OnEquals { get; set; }
26 |  
27 |         internal Func OnGetHashCode { get; set; }
28 |     }
29 | 
30 |     internal class DelegatingEqualityComparer : IEqualityComparer
31 |     {
32 |         public DelegatingEqualityComparer()
33 |         {
34 |             this.OnEquals = (x, y) => false;
35 |             this.OnGetHashCode = x => 0;
36 |         }
37 | 
38 |         public bool Equals(T x, T y)
39 |         {
40 |             return this.OnEquals(x, y);
41 |         }
42 | 
43 |         public int GetHashCode(T obj)
44 |         {
45 |             return this.OnGetHashCode(obj);
46 |         }
47 | 
48 |         internal Func OnEquals { get; set; }
49 | 
50 |         internal Func OnGetHashCode { get; set; }
51 |     }
52 | }
53 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/DelegatingMemberComparer.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Reflection;
 3 | using SemanticComparison;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     internal class DelegatingMemberComparer : IMemberComparer
 8 |     {
 9 |         internal DelegatingMemberComparer()
10 |         {
11 |             this.OnIsSatisfiedByProperty = x => false;
12 |             this.OnIsSatisfiedByField = x => false;
13 |             this.OnEquals = (x, y) => false;
14 |         }
15 | 
16 |         public bool IsSatisfiedBy(PropertyInfo pi)
17 |         {
18 |             return this.OnIsSatisfiedByProperty(pi);
19 |         }
20 | 
21 |         public bool IsSatisfiedBy(FieldInfo fi)
22 |         {
23 |             return this.OnIsSatisfiedByField(fi);
24 |         }
25 | 
26 |         public new bool Equals(object x, object y)
27 |         {
28 |             return this.OnEquals(x, y);
29 |         }
30 | 
31 |         public int GetHashCode(object obj)
32 |         {
33 |             return obj.GetHashCode();
34 |         }
35 | 
36 |         internal Func OnIsSatisfiedByProperty { get; set; }
37 |         internal Func OnIsSatisfiedByField { get; set; }
38 |         internal Func OnEquals { get; set; }
39 |     }
40 | }
41 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/DelegatingSpecification.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using SemanticComparison;
 3 | 
 4 | namespace SemanticComparisonUnitTest
 5 | {
 6 |     internal class DelegatingSpecification : ISpecification
 7 |     {
 8 |         internal DelegatingSpecification()
 9 |         {
10 |             this.OnIsSatisfiedBy = x => false;
11 |         }
12 | 
13 |         public bool IsSatisfiedBy(T request)
14 |         {
15 |             return this.OnIsSatisfiedBy(request);
16 |         }
17 | 
18 |         internal Func OnIsSatisfiedBy { get; set; }
19 |     }
20 | }
21 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/DependencyConstraints.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using SemanticComparison;
 3 | using Xunit;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     public class DependencyConstraints
 8 |     {
 9 |         [Theory]
10 |         [InlineData("FakeItEasy")]
11 |         [InlineData("Moq")]
12 |         [InlineData("Rhino.Mocks")]
13 |         [InlineData("xunit")]
14 |         [InlineData("xunit.extensions")]
15 |         public void SemanticComparisonDoesNotReference(string assemblyName)
16 |         {
17 |             // Fixture setup
18 |             // Exercise system
19 |             var references = typeof(Likeness).GetTypeInfo().Assembly.GetReferencedAssemblies();
20 |             // Verify outcome
21 |             Assert.DoesNotContain(references, an => an.Name == assemblyName);
22 |             // Teardown
23 |         }
24 | 
25 |         [Theory]
26 |         [InlineData("FakeItEasy")]
27 |         [InlineData("Moq")]
28 |         [InlineData("Rhino.Mocks")]
29 |         public void SemanticComparisonUnitTestsDoNotReference(string assemblyName)
30 |         {
31 |             // Fixture setup
32 |             // Exercise system
33 |             var references = this.GetType().GetTypeInfo().Assembly.GetReferencedAssemblies();
34 |             // Verify outcome
35 |             Assert.DoesNotContain(references, an => an.Name == assemblyName);
36 |             // Teardown
37 |         }
38 |     }
39 | }
40 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/FalseSpecificationTest.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using SemanticComparison;
 3 | using Xunit;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     public abstract class FalseSpecificationTest
 8 |     {
 9 |         [Fact]
10 |         public void SutIsSpecification()
11 |         {
12 |             // Fixture setup
13 |             // Exercise system
14 |             var sut = new FalseSpecification();
15 |             // Verify outcome
16 |             Assert.IsAssignableFrom>(sut);
17 |             // Teardown
18 |         }
19 | 
20 |         [Fact]
21 |         public void IsSatisfiedByReturnsCorrectResult()
22 |         {
23 |             // Fixture setup
24 |             var sut = new FalseSpecification();
25 |             // Exercise system
26 |             var dummyRequest = default(T);
27 |             var result = sut.IsSatisfiedBy(dummyRequest);
28 |             // Verify outcome
29 |             Assert.False(result);
30 |             // Teardown
31 |         }
32 |     }
33 | 
34 |     public class FalseSpecificationTestOfFieldInfo : FalseSpecificationTest { }
35 |     public class FalseSpecificationTestOfMemberInfo : FalseSpecificationTest { }
36 |     public class FalseSpecificationTestOfPropertyInfo : FalseSpecificationTest { }
37 | }
38 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/LikenessExceptionTest.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using SemanticComparison;
 3 | using Xunit;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     public class LikenessExceptionTest
 8 |     {
 9 |         [Fact]
10 |         public void SutIsException()
11 |         {
12 |             // Fixture setup
13 |             // Exercise system
14 |             var sut = new LikenessException();
15 |             // Verify outcome
16 |             Assert.IsAssignableFrom(sut);
17 |             // Teardown
18 |         }
19 | 
20 |         [Fact]
21 |         public void SutHasDefaultConstructor()
22 |         {
23 |             // Fixture setup
24 |             // Exercise system and verify outcome
25 |             Assert.Null(Record.Exception(() =>
26 |                 new LikenessException()
27 |             ));
28 |             // Teardown
29 |         }
30 | 
31 |         [Fact]
32 |         public void InitializedWithDefaultConstructorHasMessage()
33 |         {
34 |             // Fixture setup
35 |             var sut = new LikenessException();
36 |             // Exercise system
37 |             var result = sut.Message;
38 |             // Verify outcome
39 |             Assert.False(string.IsNullOrEmpty(result));
40 |             // Teardown
41 |         }
42 | 
43 |         [Fact]
44 |         public void InitializedWithMessageHasCorrectMessage()
45 |         {
46 |             // Fixture setup
47 |             var expectedMessage = Guid.NewGuid().ToString();
48 |             var sut = new LikenessException(expectedMessage);
49 |             // Exercise system
50 |             var result = sut.Message;
51 |             // Verify outcome
52 |             Assert.Equal(expectedMessage, result);
53 |             // Teardown
54 |         }
55 | 
56 |         [Fact]
57 |         public void InitializedWithMessageAndInnerExceptionHasCorrectMessage()
58 |         {
59 |             // Fixture setup
60 |             var expectedMessage = Guid.NewGuid().ToString();
61 |             var dummyException = new Exception();
62 |             var sut = new LikenessException(expectedMessage, dummyException);
63 |             // Exercise system
64 |             var result = sut.Message;
65 |             // Verify outcome
66 |             Assert.Equal(expectedMessage, result);
67 |             // Teardown
68 |         }
69 | 
70 |         [Fact]
71 |         public void InitializedWithMessageAndInnerExceptionHasInnerException()
72 |         {
73 |             // Fixture setup
74 |             var dummyMessage = "Anonymous text";
75 |             var expectedException = new Exception();
76 |             var sut = new LikenessException(dummyMessage, expectedException);
77 |             // Exercise system
78 |             var result = sut.InnerException;
79 |             // Verify outcome
80 |             Assert.Equal(expectedException, result);
81 |             // Teardown
82 |         }
83 |     }
84 | }
85 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/LikenessSourceTest.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using SemanticComparison;
 3 | using SemanticComparison.Fluent;
 4 | using Xunit;
 5 | 
 6 | namespace SemanticComparisonUnitTest
 7 | {
 8 |     public class LikenessSourceTest
 9 |     {
10 |         [Fact]
11 |         public void ToLikenessOfNullSourceWillReturnCorrectResult()
12 |         {
13 |             // Fixture setup
14 |             var sut = new LikenessSource(null);
15 |             // Exercise system
16 |             Likeness result = sut.OfLikeness();
17 |             // Verify outcome
18 |             Assert.Null(result.Value);
19 |             // Teardown
20 |         }
21 | 
22 |         [Fact]
23 |         public void ToLikenessWillReturnCorrectResult()
24 |         {
25 |             // Fixture setup
26 |             var expectedTimeSpan = TimeSpan.FromDays(1);
27 |             var sut = new LikenessSource(expectedTimeSpan);
28 |             // Exercise system
29 |             var result = sut.OfLikeness();
30 |             // Verify outcome
31 |             Assert.Equal(expectedTimeSpan, result.Value);
32 |             // Teardown
33 |         }
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/MemberComparerTest.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Reflection;
  3 | using SemanticComparison;
  4 | using SemanticComparisonUnitTest.TestTypes;
  5 | using Xunit;
  6 | 
  7 | namespace SemanticComparisonUnitTest
  8 | {
  9 |     public class MemberComparerTest
 10 |     {
 11 |         [Fact]
 12 |         public void SutIsMemberComparer()
 13 |         {
 14 |             // Fixture setup
 15 |             var dummyComparer = new DelegatingEqualityComparer();
 16 |             var sut = new MemberComparer(dummyComparer);
 17 |             // Exercise system and verify outcome
 18 |             Assert.IsAssignableFrom(sut);
 19 |             // Teardown
 20 |         }
 21 | 
 22 |         [Fact]
 23 |         public void InitializeWithNullEqualityComparerThrows()
 24 |         {
 25 |             // Fixture setup
 26 |             // Exercise system and verify outcome
 27 |             Assert.Throws(() =>
 28 |                 new MemberComparer(null));
 29 |             // Teardown
 30 |         }
 31 | 
 32 |         [Fact]
 33 |         public void InitializeWithNullPropertySpecificationThrows()
 34 |         {
 35 |             // Fixture setup
 36 |             var dummyComparer = new DelegatingEqualityComparer();
 37 |             var dummySpecification = new DelegatingSpecification();
 38 |             // Exercise system and verify outcome
 39 |             Assert.Throws(() =>
 40 |                 new MemberComparer(
 41 |                     dummyComparer,
 42 |                     null,
 43 |                     dummySpecification));
 44 |             // Teardown
 45 |         }
 46 | 
 47 |         [Fact]
 48 |         public void InitializeWithNullFieldSpecificationThrows()
 49 |         {
 50 |             // Fixture setup
 51 |             var dummyComparer = new DelegatingEqualityComparer();
 52 |             var dummySpecification = new DelegatingSpecification();
 53 |             // Exercise system and verify outcome
 54 |             Assert.Throws(() =>
 55 |                 new MemberComparer(
 56 |                     dummyComparer,
 57 |                     dummySpecification,
 58 |                     null));
 59 |             // Teardown
 60 |         }
 61 | 
 62 |         [Fact]
 63 |         public void ComparerIsCorrect()
 64 |         {
 65 |             // Fixture setup
 66 |             var expected = new DelegatingEqualityComparer();
 67 |             var sut = new MemberComparer(expected);
 68 |             // Exercise system
 69 |             var result = sut.Comparer;
 70 |             // Verify outcome
 71 |             Assert.Equal(expected, result);
 72 |             // Teardown
 73 |         }
 74 | 
 75 |         [Fact]
 76 |         public void PropertySpecificationIsCorrect()
 77 |         {
 78 |             // Fixture setup
 79 |             var dummyComparer = new DelegatingEqualityComparer();
 80 |             var expected = new DelegatingSpecification();
 81 |             var dummySpecification = new DelegatingSpecification();
 82 | 
 83 |             var sut = new MemberComparer(
 84 |                 dummyComparer,
 85 |                 expected,
 86 |                 dummySpecification);
 87 |             // Exercise system
 88 |             var result = sut.PropertySpecification;
 89 |             // Verify outcome
 90 |             Assert.Equal(expected, result);
 91 |             // Teardown
 92 |         }
 93 | 
 94 |         [Fact]
 95 |         public void FieldSpecificationIsCorrect()
 96 |         {
 97 |             // Fixture setup
 98 |             var dummyComparer = new DelegatingEqualityComparer();
 99 |             var expected = new DelegatingSpecification();
100 |             var dummySpecification = new DelegatingSpecification();
101 | 
102 |             var sut = new MemberComparer(
103 |                 dummyComparer,
104 |                 dummySpecification,
105 |                 expected);
106 |             // Exercise system
107 |             var result = sut.FieldSpecification;
108 |             // Verify outcome
109 |             Assert.Equal(expected, result);
110 |             // Teardown
111 |         }
112 | 
113 |         [Fact]
114 |         public void IsSatisfiedByWithDefaultSpecificationForPropertyReturnsCorrectResult()
115 |         {
116 |             // Fixture setup
117 |             var property = typeof(PropertyHolder).GetProperty("Property");
118 |             var dummyComparer = new DelegatingEqualityComparer();
119 |             var sut = new MemberComparer(dummyComparer);
120 |             // Exercise system
121 |             var result = sut.IsSatisfiedBy(property);
122 |             // Verify outcome
123 |             Assert.True(result);
124 |             // Teardown
125 |         }
126 | 
127 |         [Fact]
128 |         public void IsSatisfiedByWithDefaultSpecificationForFieldReturnsCorrectResult()
129 |         {
130 |             // Fixture setup
131 |             var field = typeof(FieldHolder).GetProperty("Field");
132 |             var dummyComparer = new DelegatingEqualityComparer();
133 |             var sut = new MemberComparer(dummyComparer);
134 |             // Exercise system
135 |             var result = sut.IsSatisfiedBy(field);
136 |             // Verify outcome
137 |             Assert.True(result);
138 |             // Teardown
139 |         }
140 | 
141 |         [Theory]
142 |         [InlineData(true)]
143 |         [InlineData(false)]
144 |         public void IsSatisfiedByForPropertyReturnsCorrectResult(bool expected)
145 |         {
146 |             // Fixture setup
147 |             var property = typeof(PropertyHolder).GetProperty("Property");
148 |             var dummyComparer = new DelegatingEqualityComparer();
149 |             var dummySpecification = new DelegatingSpecification();
150 | 
151 |             var propertySpecificationStub =
152 |                 new DelegatingSpecification
153 |                 {
154 |                     OnIsSatisfiedBy = x => expected
155 |                 };
156 | 
157 |             var sut = new MemberComparer(
158 |                 dummyComparer,
159 |                 propertySpecificationStub,
160 |                 dummySpecification);
161 |             // Exercise system
162 |             var result = sut.IsSatisfiedBy(property);
163 |             // Verify outcome
164 |             Assert.Equal(expected, result);
165 |             // Teardown
166 |         }
167 | 
168 |         [Theory]
169 |         [InlineData(true)]
170 |         [InlineData(false)]
171 |         public void IsSatisfiedByForFieldReturnsCorrectResult(bool expected)
172 |         {
173 |             // Fixture setup
174 |             var field = typeof(FieldHolder).GetField("Field");
175 |             var dummyComparer = new DelegatingEqualityComparer();
176 |             var dummySpecification = new DelegatingSpecification();
177 | 
178 |             var fieldSpecificationStub =
179 |                 new DelegatingSpecification
180 |                 {
181 |                     OnIsSatisfiedBy = x => expected
182 |                 };
183 | 
184 |             var sut = new MemberComparer(
185 |                 dummyComparer,
186 |                 dummySpecification,
187 |                 fieldSpecificationStub);
188 |             // Exercise system
189 |             var result = sut.IsSatisfiedBy(field);
190 |             // Verify outcome
191 |             Assert.Equal(expected, result);
192 |             // Teardown
193 |         }
194 | 
195 |         [Theory]
196 |         [InlineData(123, 123, true)]
197 |         [InlineData(123, 321, false)]
198 |         public void EqualsForwardsCorrectCallToComparer(
199 |             object a,
200 |             object b,
201 |             bool expected)
202 |         {
203 |             // Fixture setup
204 |             var comparerStub = new DelegatingEqualityComparer
205 |             {
206 |                 OnEquals = (x, y) => x.Equals(y)
207 |             };
208 |             var sut = new MemberComparer(comparerStub);
209 |             // Exercise system
210 |             var result = sut.Equals(a, b);
211 |             // Verify outcome
212 |             Assert.Equal(expected, result);
213 |             // Teardown
214 |         }
215 | 
216 |         [Theory]
217 |         [InlineData("a", 1)]
218 |         [InlineData(123, 2)]
219 |         public void GetHashCodeForwardsCorrectCallToComparer(
220 |             object obj,
221 |             int expected)
222 |         {
223 |             // Fixture setup
224 |             var comparerStub = new DelegatingEqualityComparer
225 |             {
226 |                 OnGetHashCode = x => x == obj ? expected : 0
227 |             };
228 |             var sut = new MemberComparer(comparerStub);
229 |             // Exercise system
230 |             var result = sut.GetHashCode(obj);
231 |             // Verify outcome
232 |             Assert.Equal(expected, result);
233 |             // Teardown
234 |         }
235 |     }
236 | }


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/MemberInfoNameComparerTest.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Reflection;
 3 | using SemanticComparison;
 4 | using Xunit;
 5 | 
 6 | namespace SemanticComparisonUnitTest
 7 | {
 8 |     public class MemberInfoNameComparerTest
 9 |     {
10 |         [Fact]
11 |         public void ComparingIdenticalMembersWillReturnTrue()
12 |         {
13 |             // Fixture setup
14 |             MemberInfo mi1 = typeof(DateTime).GetProperty("Ticks");
15 |             MemberInfo mi2 = typeof(DateTime).GetProperty("Ticks");
16 |             MemberInfoNameComparer sut = new MemberInfoNameComparer();
17 |             // Exercise system
18 |             bool result = sut.Equals(mi1, mi2);
19 |             // Verify outcome
20 |             Assert.True(result, "Equals");
21 |             // Teardown
22 |         }
23 | 
24 |         [Fact]
25 |         public void ComparingDifferentMembersWillReturnFalse()
26 |         {
27 |             // Fixture setup
28 |             MemberInfo mi1 = typeof(DateTime).GetProperty("Ticks");
29 |             MemberInfo mi2 = typeof(DateTime).GetProperty("Hour");
30 |             MemberInfoNameComparer sut = new MemberInfoNameComparer();
31 |             // Exercise system
32 |             bool result = sut.Equals(mi1, mi2);
33 |             // Verify outcome
34 |             Assert.False(result, "Equals");
35 |             // Teardown
36 |         }
37 | 
38 |         [Fact]
39 |         public void ComparingNullToMemberWillReturnFalse()
40 |         {
41 |             // Fixture setup
42 |             MemberInfo mi = typeof(DateTime).GetProperty("Ticks");
43 |             MemberInfo nullMemberInfo = null;
44 |             MemberInfoNameComparer sut = new MemberInfoNameComparer();
45 |             // Exercise system
46 |             bool result = sut.Equals(mi, nullMemberInfo);
47 |             // Verify outcome
48 |             Assert.False(result, "Equals");
49 |             // Teardown
50 |         }
51 | 
52 |         [Fact]
53 |         public void ComparingMemberToNullWillReturnFalse()
54 |         {
55 |             // Fixture setup
56 |             MemberInfo nullMemberInfo = null;
57 |             MemberInfo mi = typeof(DateTime).GetProperty("Ticks");
58 |             MemberInfoNameComparer sut = new MemberInfoNameComparer();
59 |             // Exercise system
60 |             bool result = sut.Equals(nullMemberInfo, mi);
61 |             // Verify outcome
62 |             Assert.False(result, "Equals");
63 |             // Teardown
64 |         }
65 | 
66 |         [Fact]
67 |         public void ComparingNullToNullWillReturnTrue()
68 |         {
69 |             // Fixture setup
70 |             var sut = new MemberInfoNameComparer();
71 |             // Exercise system
72 |             bool result = sut.Equals(null, null);
73 |             // Verify outcome
74 |             Assert.True(result, "Equals");
75 |             // Teardown
76 |         }
77 | 
78 |         [Fact]
79 |         public void GetHashCodeOfNullSutShouldNotThrowAsExceptionIsNotExpectedThere()
80 |         {
81 |             // Fixture setup
82 |             var sut = new MemberInfoNameComparer();
83 |             // Exercise system and verify outcome
84 |             Assert.Null(Record.Exception(() =>
85 |                 sut.GetHashCode(null)));
86 |             // Teardown
87 |         }
88 |     }
89 | }
90 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.InteropServices;
 3 | 
 4 | // General Information about an assembly is controlled through the following 
 5 | // set of attributes. Change these attribute values to modify the information
 6 | // associated with an assembly.
 7 | [assembly: AssemblyCulture("")]
 8 | 
 9 | // Setting ComVisible to false makes the types in this assembly not visible 
10 | // to COM componenets.  If you need to access a type in this assembly from 
11 | // COM, set the ComVisible attribute to true on that type.
12 | [assembly: ComVisible(false)]
13 | 
14 | // The following GUID is for the ID of the typelib if this project is exposed to COM
15 | [assembly: Guid("548f4588-6f76-42a6-b717-23ff429e9e74")]
16 | 
17 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/ProxyCreationExceptionTest.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using SemanticComparison;
 3 | using Xunit;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     public class ProxyCreationExceptionTest
 8 |     {
 9 |         [Fact]
10 |         public void SutIsException()
11 |         {
12 |             // Fixture setup
13 |             // Exercise system
14 |             var sut = new ProxyCreationException();
15 |             // Verify outcome
16 |             Assert.IsAssignableFrom(sut);
17 |             // Teardown
18 |         }
19 | 
20 |         [Fact]
21 |         public void SutHasDefaultConstructor()
22 |         {
23 |             // Fixture setup
24 |             // Exercise system and verify outcome
25 |             Assert.Null(Record.Exception(() =>
26 |                 new ProxyCreationException()));
27 |             // Teardown
28 |         }
29 | 
30 |         [Fact]
31 |         public void InitializedWithDefaultConstructorHasMessage()
32 |         {
33 |             // Fixture setup
34 |             var sut = new ProxyCreationException();
35 |             // Exercise system
36 |             var result = sut.Message;
37 |             // Verify outcome
38 |             Assert.False(string.IsNullOrEmpty(result));
39 |             // Teardown
40 |         }
41 | 
42 |         [Fact]
43 |         public void InitializedWithMessageHasCorrectMessage()
44 |         {
45 |             // Fixture setup
46 |             var expectedMessage = Guid.NewGuid().ToString();
47 |             var sut = new ProxyCreationException(expectedMessage);
48 |             // Exercise system
49 |             var result = sut.Message;
50 |             // Verify outcome
51 |             Assert.Equal(expectedMessage, result);
52 |             // Teardown
53 |         }
54 | 
55 |         [Fact]
56 |         public void InitializedWithMessageAndInnerExceptionHasCorrectMessage()
57 |         {
58 |             // Fixture setup
59 |             var expectedMessage = Guid.NewGuid().ToString();
60 |             var dummyException = new Exception();
61 |             var sut = new ProxyCreationException(expectedMessage, dummyException);
62 |             // Exercise system
63 |             var result = sut.Message;
64 |             // Verify outcome
65 |             Assert.Equal(expectedMessage, result);
66 |             // Teardown
67 |         }
68 | 
69 |         [Fact]
70 |         public void InitializedWithMessageAndInnerExceptionHasInnerException()
71 |         {
72 |             // Fixture setup
73 |             var dummyMessage = "Anonymous text";
74 |             var expectedException = new Exception();
75 |             var sut = new ProxyCreationException(dummyMessage, expectedException);
76 |             // Exercise system
77 |             var result = sut.InnerException;
78 |             // Verify outcome
79 |             Assert.Equal(expectedException, result);
80 |             // Teardown
81 |         }
82 |     }
83 | }


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/SemanticComparisonUnitTest.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 |   
 3 | 
 4 |   
 5 |     net452;netcoreapp2.1
 6 |     SemanticComparisonUnitTest
 7 |     SemanticComparison.UnitTest
 8 | 
 9 |     False
10 |     false
11 | 
12 |     true
13 |     true
14 | 
15 |     false
16 |     ..\Empty.ruleset
17 | 
18 |     false
19 |     
20 |     false
21 |   
22 | 
23 | 
24 |   
25 |     
26 |     
27 | 
28 |     
29 |   
30 | 
31 |   
32 |     
33 |   
34 | 
35 |   
36 |     
37 |   
38 | 
39 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/AbstractType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public abstract class AbstractType
 4 |     {
 5 |         protected AbstractType()
 6 |         {
 7 |         }
 8 | 
 9 |         public object Property1 { get; set; }
10 | 
11 |         public object Property2 { get; set; }
12 | 
13 |         public object Property3 { get; set; }
14 | 
15 |         public virtual object Property4 { get; set; }
16 | 
17 |         public object Field1;
18 |     }
19 | }
20 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/AbstractTypeWithNonDefaultConstructor.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public abstract class AbstractTypeWithNonDefaultConstructor
 6 |     {
 7 |         protected AbstractTypeWithNonDefaultConstructor(T value)
 8 |         {
 9 |             if (value == null)
10 |             {
11 |                 throw new ArgumentNullException(nameof(value));
12 |             }
13 | 
14 |             this.Property = value;
15 |         }
16 | 
17 |         public T Property { get; }
18 |     }
19 | }
20 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/ComplexClass.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class ComplexClass
 6 |     {
 7 |         public int Number { get; set; }
 8 | 
 9 |         public string Text { get; set; }
10 | 
11 |         public Version Version { get; set; }
12 | 
13 |         public OperatingSystem OperatingSystem { get; set; }
14 | 
15 |         public ValueObject Value { get; set; }
16 | 
17 |         public Entity Entity { get; set; }
18 |     }
19 | }
20 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/CompositeType.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Collections.Generic;
 3 | using System.Linq;
 4 | 
 5 | namespace SemanticComparisonUnitTest.TestTypes
 6 | {
 7 |     public class CompositeType : AbstractType
 8 |     {
 9 |         public CompositeType(IEnumerable types)
10 |             : this(types.ToArray())
11 |         {
12 |         }
13 | 
14 |         public CompositeType(params AbstractType[] types)
15 |         {
16 |             if (types == null)
17 |             {
18 |                 throw new ArgumentNullException(nameof(types));
19 |             }
20 | 
21 |             this.Types = types;
22 |         }
23 | 
24 |         public IEnumerable Types { get; }
25 |     }
26 | }


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/ConcreteType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class ConcreteType : AbstractType
 4 |     {
 5 |         public ConcreteType()
 6 |         {
 7 |         }
 8 | 
 9 |         public ConcreteType(object obj)
10 |         {
11 |             this.Property1 = obj;
12 |         }
13 | 
14 |         public ConcreteType(object obj1, object obj2)
15 |         {
16 |             this.Property1 = obj1;
17 |             this.Property2 = obj2;
18 |         }
19 | 
20 |         public ConcreteType(object obj1, object obj2, object obj3)
21 |         {
22 |             this.Property1 = obj1;
23 |             this.Property2 = obj2;
24 |             this.Property3 = obj3;
25 |         }
26 | 
27 |         public ConcreteType(object obj1, object obj2, object obj3, object obj4)
28 |         {
29 |             this.Property1 = obj1;
30 |             this.Property2 = obj2;
31 |             this.Property3 = obj3;
32 |             this.Property4 = obj4;
33 |         }
34 | 
35 |         public override object Property4 { get; set; }
36 | 
37 |         public object Property5 { get; set; }
38 |     }
39 | }
40 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/DataErrorInfo.cs:
--------------------------------------------------------------------------------
 1 | #if SYSTEM_COMPONENTSETTINGS_DATAERRORINFO
 2 | using System.ComponentModel;
 3 | 
 4 | namespace SemanticComparisonUnitTest.TestTypes
 5 | {
 6 |     public class DataErrorInfo : IDataErrorInfo
 7 |     {
 8 |         public string Error
 9 |         {
10 |             get { return string.Empty; }
11 |         }
12 | 
13 |         public string this[string columnName]
14 |         {
15 |             get { return string.Empty; }
16 |         }
17 |     }
18 | }
19 | #endif


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/DoubleFieldHolder.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class DoubleFieldHolder
 4 |     {
 5 |         public T1 Field1;
 6 | 
 7 |         public T2 Field2;
 8 |     }
 9 | }
10 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/DoubleParameterType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class DoubleParameterType
 4 |     {
 5 |         public DoubleParameterType(T1 parameter1, T2 parameter2)
 6 |         {
 7 |             this.Parameter1 = parameter1;
 8 |             this.Parameter2 = parameter2;
 9 |         }
10 | 
11 |         public T1 Parameter1 { get; private set; }
12 | 
13 |         public T2 Parameter2 { get; private set; }
14 |     }
15 | }
16 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/DoublePropertyHolder.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class DoublePropertyHolder
 4 |     {
 5 |         public T1 Property1 { get; set; }
 6 | 
 7 |         public T2 Property2 { get; set; }
 8 |     }
 9 | }
10 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/Entity.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class Entity
 6 |     {
 7 |         public readonly string name;
 8 |         public readonly Guid id;
 9 | 
10 |         public Entity(string name)
11 |         {
12 |             this.name = name;
13 |             this.id = Guid.NewGuid();
14 |         }
15 | 
16 |         public string Name
17 |         {
18 |             get { return this.name; }
19 |         }
20 | 
21 |         public Guid Id
22 |         {
23 |             get { return this.id; }
24 |         }
25 | 
26 |         public override bool Equals(object obj)
27 |         {
28 |             var other = obj as Entity;
29 |             if (other != null)
30 |                 return this.Id.Equals(other.Id);
31 |             return base.Equals(obj);
32 |         }
33 | 
34 |         public override int GetHashCode()
35 |         {
36 |             return this.Id.GetHashCode();
37 |         }
38 |     }
39 | }
40 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/EqualityResponder.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class EqualityResponder
 4 |     {
 5 |         private readonly bool equals;
 6 | 
 7 |         public EqualityResponder(bool equals)
 8 |         {
 9 |             this.equals = equals;
10 |         }
11 | 
12 |         public override bool Equals(object obj)
13 |         {
14 |             return this.equals;
15 |         }
16 | 
17 |         public override int GetHashCode()
18 |         {
19 |             return this.equals.GetHashCode();
20 |         }
21 |     }
22 | }
23 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/FieldHolder.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticComparisonUnitTest.TestTypes
2 | {
3 |     public class FieldHolder
4 |     {
5 |         public T Field;
6 |     }
7 | }
8 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/PropertyHolder.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class PropertyHolder
 4 |     {
 5 |         public T Property { get; set; }
 6 | 
 7 |         public void SetProperty(T value)
 8 |         {
 9 |             this.Property = value;
10 |         }
11 |     }
12 | }
13 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/PublicSealedType.cs:
--------------------------------------------------------------------------------
1 | namespace SemanticComparisonUnitTest.TestTypes
2 | {
3 |     public sealed class PublicSealedType
4 |     {
5 |     }
6 | }
7 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/QuadrupleParameterType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class QuadrupleParameterType
 4 |     {
 5 |         public QuadrupleParameterType(T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4)
 6 |         {
 7 |             this.Parameter1 = parameter1;
 8 |             this.Parameter2 = parameter2;
 9 |             this.Parameter3 = parameter3;
10 |             this.Parameter4 = parameter4;
11 |         }
12 | 
13 |         public T1 Parameter1 { get; private set; }
14 | 
15 |         public T2 Parameter2 { get; private set; }
16 | 
17 |         public T3 Parameter3 { get; private set; }
18 | 
19 |         public T4 Parameter4 { get; private set; }
20 |     }
21 | }
22 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/SingleParameterType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class SingleParameterType
 4 |     {
 5 |         public SingleParameterType(T parameter)
 6 |         {
 7 |             this.Parameter = parameter;
 8 |         }
 9 | 
10 |         public T Parameter { get; private set; }
11 |     }
12 | }
13 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TripleParameterType.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TripleParameterType
 4 |     {
 5 |         public TripleParameterType(T1 parameter1, T2 parameter2, T3 parameter3)
 6 |         {
 7 |             this.Parameter1 = parameter1;
 8 |             this.Parameter2 = parameter2;
 9 |             this.Parameter3 = parameter3;
10 |         }
11 | 
12 |         public T1 Parameter1 { get; private set; }
13 | 
14 |         public T2 Parameter2 { get; private set; }
15 | 
16 |         public T3 Parameter3 { get; private set; }
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeOverridingGetHashCode.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeOverridingGetHashCode
 4 |     {
 5 |         public override int GetHashCode()
 6 |         {
 7 |             return 14;
 8 |         }
 9 |     }
10 | }
11 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithDifferentParameterTypesAndProperties.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class TypeWithDifferentParameterTypesAndProperties
 6 |     {
 7 |         public TypeWithDifferentParameterTypesAndProperties(
 8 |             double field1,
 9 |             string field2,
10 |             int field3)
11 |             : this(field1, field2, field3, Guid.NewGuid())
12 |         {
13 |         }
14 | 
15 |         public TypeWithDifferentParameterTypesAndProperties(
16 |             double field1,
17 |             string field2,
18 |             int field3,
19 |             Guid field4)
20 |         {
21 |             this.Property1 = field1;
22 |             this.Property2 = field2;
23 |             this.Property3 = field3;
24 |             this.Property4 = field4;
25 |         }
26 | 
27 |         protected TypeWithDifferentParameterTypesAndProperties(object source)
28 |         {
29 |             if (source == null)
30 |             {
31 |                 throw new ArgumentNullException(nameof(source));
32 |             }
33 |         }
34 | 
35 |         public double Property1 { get; }
36 | 
37 |         public string Property2 { get; }
38 | 
39 |         public int Property3 { get; }
40 | 
41 |         public Guid Property4 { get; }
42 |     }
43 | }
44 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithIdenticalParameterTypesAndProperties.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class TypeWithIdenticalParameterTypesAndProperties
 6 |     {
 7 |         public TypeWithIdenticalParameterTypesAndProperties(
 8 |             long parameter1,
 9 |             long parameter2,
10 |             long parameter3)
11 |         {
12 |             this.Property1 = parameter1;
13 |             this.Property2 = parameter2;
14 |             this.Property3 = parameter3;
15 |             this.Property4 = 400;
16 |         }
17 | 
18 |         protected TypeWithIdenticalParameterTypesAndProperties(object source)
19 |         {
20 |             if (source == null)
21 |             {
22 |                 throw new ArgumentNullException(nameof(source));
23 |             }
24 |         }
25 | 
26 |         public long Property1 { get; }
27 | 
28 |         public long Property2 { get; }
29 | 
30 |         public long Property3 { get; }
31 | 
32 |         public long Property4 { get; }
33 |     }
34 | }
35 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithIncompatibleAndCompatibleConstructor.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeWithIncompatibleAndCompatibleConstructor
 4 |     {
 5 |         public TypeWithIncompatibleAndCompatibleConstructor(ConcreteType a)
 6 |             : this(new ConcreteType(), new CompositeType(a), new byte())
 7 |         {
 8 |         }
 9 | 
10 |         public TypeWithIncompatibleAndCompatibleConstructor(
11 |             ConcreteType a, 
12 |             byte b)
13 |             : this(new ConcreteType(), new CompositeType(a), b)
14 |         {
15 |         }
16 | 
17 |         public TypeWithIncompatibleAndCompatibleConstructor(
18 |             ConcreteType a, 
19 |             AbstractType b, 
20 |             byte c)
21 |         {
22 |             this.Property1 = a;
23 |             this.Property2 = b;
24 |             this.Property3 = c;
25 |         }
26 | 
27 |         public AbstractType Property1 { get; }
28 | 
29 |         public AbstractType Property2 { get; }
30 | 
31 |         public byte Property3 { get; }
32 |     }
33 | }
34 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithIndexer.cs:
--------------------------------------------------------------------------------
 1 | using System.Collections.Generic;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class TypeWithIndexer
 6 |     {
 7 |         private readonly Dictionary dict;
 8 | 
 9 |         public TypeWithIndexer()
10 |         {
11 |             this.dict = new Dictionary();
12 |         }
13 | 
14 |         public string this[string index] 
15 |         {
16 |             get
17 |             {
18 |                 return this.dict[index];
19 |             }
20 |             set
21 |             {
22 |                 this.dict[index] = value;
23 |             }
24 |         }
25 |     }
26 | }
27 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithOverloadedMembers.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeWithOverloadedMembers
 4 |     {
 5 |         public object SomeProperty { get; set; }
 6 | 
 7 |         public void DoSomething()
 8 |         {
 9 |         }
10 | 
11 |         public void DoSomething(object obj)
12 |         {
13 |         }
14 | 
15 |         public void DoSomething(object x, object y)
16 |         {
17 |         }
18 | 
19 |         public void DoSomething(object x, object y, object z)
20 |         {
21 |         }
22 |     }
23 | }
24 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithPrivateDefaultCtorAndOtherCtor.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace SemanticComparisonUnitTest.TestTypes
 4 | {
 5 |     public class TypeWithPrivateDefaultCtorAndOtherCtor
 6 |     {
 7 |         private TypeWithPrivateDefaultCtorAndOtherCtor()
 8 |         {
 9 |             
10 |         }
11 |         public TypeWithPrivateDefaultCtorAndOtherCtor(T value) : this()
12 |         {
13 |             if (value == null)
14 |             {
15 |                 throw new ArgumentNullException(nameof(value));
16 |             }
17 | 
18 |             this.Property = value;
19 |         }
20 | 
21 |         public T Property { get; }
22 |     }
23 | }


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithPublicFieldsAndProperties.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeWithPublicFieldsAndProperties
 4 |     {
 5 |         public string Field;
 6 | 
 7 |         public long Number { get; set; }
 8 | 
 9 |         public decimal AutomaticProperty { get; set; }
10 |     }
11 | }
12 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithSimilarPropertyNamesAndIdenticalPropertyTypes.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeWithSimilarPropertyNamesAndIdenticalPropertyTypes
 4 |     {
 5 |         public int Property { get; set; }
 6 | 
 7 |         public int Property2 { get; set; }
 8 |     }
 9 | }
10 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/TypeWithUnorderedProperties.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class TypeWithUnorderedProperties
 4 |     {
 5 |         public TypeWithUnorderedProperties(ConcreteType a, AbstractType b, byte c)
 6 |         {
 7 |             this.Property1 = a;
 8 |             this.Property2 = b;
 9 |             this.Property3 = c;
10 |         }
11 | 
12 |         public byte Property3 { get; }
13 | 
14 |         public AbstractType Property1 { get; }
15 | 
16 |         public AbstractType Property2 { get; }
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TestTypes/ValueObject.cs:
--------------------------------------------------------------------------------
 1 | namespace SemanticComparisonUnitTest.TestTypes
 2 | {
 3 |     public class ValueObject
 4 |     {
 5 |         public readonly int x;
 6 |         public readonly int y;
 7 | 
 8 |         public ValueObject(int x, int y)
 9 |         {
10 |             this.x = x;
11 |             this.y = y;
12 |         }
13 | 
14 |         public int X
15 |         {
16 |             get { return x; }
17 |         }
18 | 
19 |         public int Y
20 |         {
21 |             get { return y; }
22 |         }
23 | 
24 |         public override bool Equals(object obj)
25 |         {
26 |             var other = obj as ValueObject;
27 |             if (other != null)
28 |                 return this.X == other.X
29 |                     && this.Y == other.Y;
30 |             return base.Equals(obj);
31 |         }
32 | 
33 |         public override int GetHashCode()
34 |         {
35 |             return
36 |                 this.X.GetHashCode() ^
37 |                 this.Y.GetHashCode();
38 |         }
39 |     }
40 | }
41 | 


--------------------------------------------------------------------------------
/Src/SemanticComparisonUnitTest/TrueSpecificationTest.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using SemanticComparison;
 3 | using Xunit;
 4 | 
 5 | namespace SemanticComparisonUnitTest
 6 | {
 7 |     public abstract class TrueSpecificationTest
 8 |     {
 9 |         [Fact]
10 |         public void SutIsSpecification()
11 |         {
12 |             // Fixture setup
13 |             // Exercise system
14 |             var sut = new TrueSpecification();
15 |             // Verify outcome
16 |             Assert.IsAssignableFrom>(sut);
17 |             // Teardown
18 |         }
19 | 
20 |         [Fact]
21 |         public void IsSatisfiedByReturnsCorrectResult()
22 |         {
23 |             // Fixture setup
24 |             var sut = new TrueSpecification();
25 |             // Exercise system
26 |             var dummyRequest = default(T);
27 |             var result = sut.IsSatisfiedBy(dummyRequest);
28 |             // Verify outcome
29 |             Assert.True(result);
30 |             // Teardown
31 |         }
32 |     }
33 | 
34 |     public class TrueSpecificationTestOfFieldInfo : TrueSpecificationTest { }
35 |     public class TrueSpecificationTestOfMemberInfo : TrueSpecificationTest { }
36 |     public class TrueSpecificationTestOfPropertyInfo : TrueSpecificationTest { }
37 | }
38 | 


--------------------------------------------------------------------------------
/Src/TestTypeFoundation/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.InteropServices;
 3 | 
 4 | [assembly: AssemblyCulture("")]
 5 | 
 6 | // Setting ComVisible to false makes the types in this assembly not visible 
 7 | // to COM components.  If you need to access a type in this assembly from 
 8 | // COM, set the ComVisible attribute to true on that type.
 9 | [assembly: ComVisible(false)]
10 | 
11 | // The following GUID is for the ID of the typelib if this project is exposed to COM
12 | [assembly: Guid("7ef374e5-5287-4977-a405-2b330be7fd26")]
13 | 


--------------------------------------------------------------------------------
/Src/TestTypeFoundation/TestTypeFoundation.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 |   
 3 |   
 4 | 
 5 |   
 6 |     net452;netstandard1.2
 7 |     TestTypeFoundation
 8 |     TestTypeFoundation
 9 |   
10 |  
11 | 
12 | 
13 | 


--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
 1 | image: Visual Studio 2017
 2 | 
 3 | environment:
 4 |   NUGET_API_KEY:
 5 |     secure: Mr30wh1prFHq1sfPS7zLxhJp1M8N5qxjQNQthXdCLYAJgOfR9P0uq3iq8UAycN26
 6 |   MYGET_API_KEY: dummy
 7 | 
 8 | pull_requests:
 9 |   do_not_increment_build_number: true
10 | 
11 | # Is required by SourceLink to have valid file hashes.
12 | # See more detail here: https://github.com/ctaggart/SourceLink/wiki/Line-Endings
13 | init:
14 |   - git config --global core.autocrlf input
15 | 
16 | build_script:
17 | - ps: |
18 |     & .\build.cmd AppVeyor NuGetPublicKey="$($Env:NUGET_API_KEY)" NuGetPrivateKey="$($Env:MYGET_API_KEY)" BuildVersion=git BuildNumber=$($Env:APPVEYOR_BUILD_NUMBER)
19 | 
20 | test: off
21 | 
22 | artifacts:
23 | - path: build\NuGetPackages\*.nupkg
24 |   name: NuGet
25 | 
26 | deploy: off
27 | 
28 | 


--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
 1 | @echo off
 2 | cls
 3 | 
 4 | SET BUILD_DIR=build
 5 | SET TOOLS_DIR=%BUILD_DIR%\tools
 6 | SET NUGET_PATH=%TOOLS_DIR%\nuget.exe
 7 | 
 8 | IF NOT EXIST %TOOLS_DIR%\ (
 9 |   mkdir %TOOLS_DIR%
10 | )
11 | 
12 | IF NOT EXIST %NUGET_PATH% (
13 |   echo Downloading NuGet.exe ...
14 |   powershell -Command "Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/v4.3.0/nuget.exe -OutFile %NUGET_PATH%"
15 | )
16 | 
17 | IF NOT EXIST "%TOOLS_DIR%\FAKE.Core\tools\Fake.exe" (
18 |   %NUGET_PATH% install "FAKE.Core" -Version 4.63.2 -OutputDirectory %TOOLS_DIR% -ExcludeVersion 
19 | )
20 | 
21 | echo Running FAKE Build...
22 | %TOOLS_DIR%\FAKE.Core\tools\Fake.exe build.fsx %* -BuildDir=%BUILD_DIR%
23 | 


--------------------------------------------------------------------------------