diff --git a/.editorconfig b/.editorconfig index f04d5cb..ce4bcae 100644 --- a/.editorconfig +++ b/.editorconfig @@ -61,15 +61,14 @@ csharp_style_conditional_delegate_call = true:suggestion csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_members_in_anonymous_types = true ## Naming +### private fields should be _camelCase + dotnet_naming_style.underscore_prefix.capitalization = camel_case dotnet_naming_style.underscore_prefix.required_prefix = _ -# private fields should be _camelCase dotnet_naming_rule.private_fields_with_underscore.symbols = private_fields dotnet_naming_rule.private_fields_with_underscore.style = underscore_prefix dotnet_naming_rule.private_fields_with_underscore.severity = suggestion diff --git a/.gitignore b/.gitignore index 3c0016d..86e8e12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ *.user *.opencover.xml +*.orig .idea bin obj +BenchmarkDotNet.Artifacts diff --git a/README.md b/README.md index 0742761..d60b15e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Declare class: ```c# -class UserInfo +class User { public string FirstName { get; set; } public string LastName { get; set; } @@ -27,8 +27,8 @@ class UserInfo Configure Func: ```c# -var fingerprint = FingerprintBuilder - .Create(SHA256.Create().ComputeHash) +var sha256 = FingerprintBuilder + .Create(SHA256.Create()) .For(p => p.FirstName) .For(p => p.LastName) .Build(); @@ -37,29 +37,29 @@ var fingerprint = FingerprintBuilder Get hash: ```c# -var user = new UserInfo { FirstName = "John", LastName = "Smith" }; -var hash = fingerprint(user).ToLowerHexString(); // 9996c4bbc1da4938144886b27b7c680e75932b5a56d911754d75ae4e0a9b4f1a +var user = new User { FirstName = "John", LastName = "Smith" }; +var hash = sha256(user).ToLowerHexString(); // 62565a67bf16004038c502eb68907411fcf7871c66ee01a1aa274cc18d9fb541 ``` ## Benchmarks ```ini -BenchmarkDotNet=v0.12.1, OS=arch + +BenchmarkDotNet=v0.13.5, OS=arch Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET Core SDK=3.1.300 - [Host] : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT - Job-PCQRMO : .NET Core 3.1.4 (CoreCLR 4.700.20.20201, CoreFX 4.700.20.22101), X64 RyuJIT +.NET SDK=7.0.103 + [Host] : .NET 7.0.3 (7.0.323.12801), X64 RyuJIT AVX2 + DefaultJob : .NET 7.0.3 (7.0.323.12801), X64 RyuJIT AVX2 -Runtime=.NET Core 3.1 IterationCount=50 LaunchCount=2 -RunStrategy=Throughput WarmupCount=10 ``` - | Method | Mean | Error | StdDev | Min | Max | Median | |-------------------- |---------:|----------:|----------:|---------:|---------:|---------:| -| MD5_Model_To_Hex | 4.277 μs | 0.0763 μs | 0.2128 μs | 4.007 μs | 4.612 μs | 4.275 μs | -| SHA1_Model_To_Hex | 4.303 μs | 0.0232 μs | 0.0639 μs | 4.178 μs | 4.475 μs | 4.300 μs | -| SHA256_Model_To_Hex | 5.183 μs | 0.0526 μs | 0.1500 μs | 4.987 μs | 5.627 μs | 5.151 μs | -| SHA512_Model_To_Hex | 6.842 μs | 0.0688 μs | 0.1908 μs | 6.626 μs | 7.470 μs | 6.795 μs | +| MD5_Model_To_Hex | 2.142 μs | 0.0142 μs | 0.0118 μs | 2.125 μs | 2.163 μs | 2.146 μs | +| SHA1_Model_To_Hex | 2.379 μs | 0.0155 μs | 0.0121 μs | 2.355 μs | 2.400 μs | 2.384 μs | +| SHA256_Model_To_Hex | 3.059 μs | 0.0245 μs | 0.0217 μs | 3.031 μs | 3.107 μs | 3.054 μs | +| SHA512_Model_To_Hex | 4.564 μs | 0.0182 μs | 0.0161 μs | 4.540 μs | 4.598 μs | 4.563 μs | + + ## License diff --git a/src/FingerprintBuilder.cs b/src/FingerprintBuilder.cs index c22843c..9f22fc1 100644 --- a/src/FingerprintBuilder.cs +++ b/src/FingerprintBuilder.cs @@ -1,76 +1,158 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Linq.Expressions; -using System.Runtime.Serialization.Formatters.Binary; +using System.Security.Cryptography; -namespace FingerprintBuilder +namespace FingerprintBuilder; + +public class FingerprintBuilder : IFingerprintBuilder { - public class FingerprintBuilder : IFingerprintBuilder + private readonly Func _computeHash; + private readonly IDictionary> _fingerprints = new SortedDictionary>(StringComparer.OrdinalIgnoreCase); + + private readonly Type[] _supportedTypes = { - private readonly Func _computeHash; - private readonly IDictionary> _fingerprints; + typeof(bool), + typeof(byte), + typeof(sbyte), + typeof(byte[]), + typeof(char), + typeof(char[]), + typeof(double), + typeof(decimal), + typeof(short), + typeof(ushort), + typeof(int), + typeof(uint), + typeof(long), + typeof(ulong), + typeof(float), + typeof(string) + }; - private FingerprintBuilder(Func computeHash) - { - _computeHash = computeHash ?? throw new ArgumentNullException(nameof(computeHash)); - _fingerprints = new SortedDictionary>(StringComparer.OrdinalIgnoreCase); - } + private FingerprintBuilder(Func computeHash) + { + _computeHash = computeHash ?? throw new ArgumentNullException(nameof(computeHash)); + } - public static IFingerprintBuilder Create(Func computeHash) => - new FingerprintBuilder(computeHash); + public static IFingerprintBuilder Create(HashAlgorithm hashAlgorithm) => Create(hashAlgorithm.ComputeHash); - public IFingerprintBuilder For(Expression> expression) => - For(expression, _ => _); + public static IFingerprintBuilder Create(Func computeHash) => new FingerprintBuilder(computeHash); - public IFingerprintBuilder For(Expression> expression, Expression> fingerprint) => - For(expression, fingerprint); + public IFingerprintBuilder For(Expression> expression) => For(expression, f => f); - public IFingerprintBuilder For(Expression> expression, Expression> fingerprint) + public IFingerprintBuilder For(Expression> expression, bool toLower, bool trim) + { + var format = (Func)(input => { - return For(expression, fingerprint); - } + if (toLower) + input = input.ToLowerInvariant(); - private IFingerprintBuilder For(Expression> expression, Expression> fingerprint) - { - if (!(expression.Body is MemberExpression memberExpression)) - throw new ArgumentException("Expression must be a member expression"); + if (trim) + input = input.Trim(); - if (_fingerprints.ContainsKey(memberExpression.Member.Name)) - throw new ArgumentException($"Member {memberExpression.Member.Name} has already been added."); + return input; + }); - var getValue = expression.Compile(); - var getFingerprint = fingerprint.Compile(); + return For(expression, input => format(input)); + } - _fingerprints[memberExpression.Member.Name] = obj => - { - var value = getValue(obj); - return value == null ? default : getFingerprint(value); - }; + public IFingerprintBuilder For(Expression> expression, Expression> fingerprint) => + For(expression, fingerprint); - return this; - } + private IFingerprintBuilder For(Expression> expression, Expression> fingerprint) + { + if (expression.Body is not MemberExpression memberExpression) + throw new ArgumentException("Expression must be a member expression"); - public Func Build() + var memberName = memberExpression.Member.Name; + + if (_fingerprints.ContainsKey(memberExpression.Member.Name)) + throw new ArgumentException("Member has already been added", memberName); + + var returnType = typeof(TReturnType); + if (!_supportedTypes.Contains(typeof(TReturnType))) + throw new ArgumentException($"Unsupported Type: {returnType.Name}", memberName); + + var getValue = expression.Compile(); + var getFingerprint = fingerprint.Compile(); + + _fingerprints[memberExpression.Member.Name] = entity => { - var binaryFormatter = new BinaryFormatter(); + var value = getValue(entity); + return value == null ? default : getFingerprint(value); + }; - return obj => + return this; + } + + public Func Build() + { + return entity => + { + using var memory = new MemoryStream(); + using var binaryWriter = new BinaryWriter(memory); + foreach (var item in _fingerprints) { - using (var memory = new MemoryStream()) + var value = item.Value(entity); + switch (value) { - foreach (var item in _fingerprints) - { - var graph = item.Value(obj); - if (graph != null) - binaryFormatter.Serialize(memory, graph); - } - - var arr = memory.ToArray(); - lock (_computeHash) - return _computeHash(arr); + case bool typedValue: + binaryWriter.Write(typedValue); + break; + case byte typedValue: + binaryWriter.Write(typedValue); + break; + case sbyte typedValue: + binaryWriter.Write(typedValue); + break; + case byte[] typedValue: + binaryWriter.Write(typedValue); + break; + case char typedValue: + binaryWriter.Write(typedValue); + break; + case char[] typedValue: + binaryWriter.Write(typedValue); + break; + case double typedValue: + binaryWriter.Write(typedValue); + break; + case decimal typedValue: + binaryWriter.Write(typedValue); + break; + case short typedValue: + binaryWriter.Write(typedValue); + break; + case ushort typedValue: + binaryWriter.Write(typedValue); + break; + case int typedValue: + binaryWriter.Write(typedValue); + break; + case uint typedValue: + binaryWriter.Write(typedValue); + break; + case long typedValue: + binaryWriter.Write(typedValue); + break; + case ulong typedValue: + binaryWriter.Write(typedValue); + break; + case float typedValue: + binaryWriter.Write(typedValue); + break; + case string typedValue: + binaryWriter.Write(typedValue); + break; } - }; - } + } + + var bytes = memory.ToArray(); + lock (_computeHash) + return _computeHash(bytes); + }; } } diff --git a/src/FingerprintBuilderExtensions.cs b/src/FingerprintBuilderExtensions.cs index 56cde0c..64acce7 100644 --- a/src/FingerprintBuilderExtensions.cs +++ b/src/FingerprintBuilderExtensions.cs @@ -1,53 +1,35 @@ using System; using System.Globalization; using System.Linq; -using System.Linq.Expressions; -namespace FingerprintBuilder +namespace FingerprintBuilder; + +public static class FingerprintBuilderExtensions { - public static class FingerprintBuilderExtensions + /// + /// Convert to LowerCase Hexadecimal string + /// + public static string ToLowerHexString(this byte[] source) { - public static IFingerprintBuilder For(this IFingerprintBuilder builder, Expression> expression, bool toLowerCase, bool ignoreWhiteSpace) - { - var format = (Func)(input => - { - if (toLowerCase) - input = input.ToLowerInvariant(); - - if (ignoreWhiteSpace) - input = input.Trim(); - - return input; - }); - - return builder.For(expression, input => format(input)); - } - - /// - /// Convert to LowerCase Hexadecimal string - /// - public static string ToLowerHexString(this byte[] source) - { - return source.ToString("x2"); - } + return source.ToString("x2"); + } - /// - /// Convert to UpperCase Hexadecimal string - /// - public static string ToUpperHexString(this byte[] source) - { - return source.ToString("X2"); - } + /// + /// Convert to UpperCase Hexadecimal string + /// + public static string ToUpperHexString(this byte[] source) + { + return source.ToString("X2"); + } - /// - /// Convert to string - /// - private static string ToString(this byte[] source, string format) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); + /// + /// Convert to string + /// + private static string ToString(this byte[] source, string format) + { + if (source == null) + throw new ArgumentNullException(nameof(source)); - return string.Join("", source.Select(ch => ch.ToString(format, CultureInfo.InvariantCulture))); - } + return string.Join("", source.Select(ch => ch.ToString(format, CultureInfo.InvariantCulture))); } } diff --git a/src/IFingerprintBuilder.cs b/src/IFingerprintBuilder.cs index bdaf298..3732bec 100644 --- a/src/IFingerprintBuilder.cs +++ b/src/IFingerprintBuilder.cs @@ -1,16 +1,15 @@ using System; using System.Linq.Expressions; -namespace FingerprintBuilder +namespace FingerprintBuilder; + +public interface IFingerprintBuilder { - public interface IFingerprintBuilder - { - IFingerprintBuilder For(Expression> expression); + IFingerprintBuilder For(Expression> expression); - IFingerprintBuilder For(Expression> expression, Expression> fingerprint); + IFingerprintBuilder For(Expression> expression, bool toLower, bool trim); - IFingerprintBuilder For(Expression> expression, Expression> fingerprint); + IFingerprintBuilder For(Expression> expression, Expression> fingerprint); - Func Build(); - } + Func Build(); } diff --git a/tests/benchmarks/FingerprintBuilder.BenchmarkTests.csproj b/tests/benchmarks/FingerprintBuilder.BenchmarkTests.csproj index ad0b378..198bca0 100644 --- a/tests/benchmarks/FingerprintBuilder.BenchmarkTests.csproj +++ b/tests/benchmarks/FingerprintBuilder.BenchmarkTests.csproj @@ -1,6 +1,6 @@  - netcoreapp3.1 + net7.0 false Exe diff --git a/tests/benchmarks/Main.cs b/tests/benchmarks/Main.cs index fbebca6..d3a231a 100644 --- a/tests/benchmarks/Main.cs +++ b/tests/benchmarks/Main.cs @@ -1,12 +1,11 @@ using BenchmarkDotNet.Running; -namespace FingerprintBuilder.BenchmarkTests +namespace FingerprintBuilder.BenchmarkTests; + +public class Program { - public class Program + private static void Main(string[] args) { - private static void Main(string[] args) - { - BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); - } + BenchmarkRunner.Run(); } -} +} \ No newline at end of file diff --git a/tests/benchmarks/ModelToHex.cs b/tests/benchmarks/ModelToHex.cs index 98615a1..be525f9 100644 --- a/tests/benchmarks/ModelToHex.cs +++ b/tests/benchmarks/ModelToHex.cs @@ -1,85 +1,81 @@ using System; using System.Security.Cryptography; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Engines; -using BenchmarkDotNet.Jobs; -namespace FingerprintBuilder.BenchmarkTests +namespace FingerprintBuilder.BenchmarkTests; + +[MeanColumn, MinColumn, MaxColumn, MedianColumn] +public class ModelToHex { - [MeanColumn, MinColumn, MaxColumn, MedianColumn] - [SimpleJob(RunStrategy.Throughput, RuntimeMoniker.NetCoreApp31, 2, 10, 50)] - public class ModelToHex - { - private Func _md5; - private Func _sha1; - private Func _sha256; - private Func _sha512; + private Func _md5; + private Func _sha1; + private Func _sha256; + private Func _sha512; - private UserInfo _user; + private UserInfo _user; - [GlobalSetup] - public void Setup() + [GlobalSetup] + public void Setup() + { + _user = new UserInfo { - _user = new UserInfo - { - FirstName = "John", - LastName = "Smith" - }; - - _md5 = FingerprintBuilder - .Create(MD5.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - _sha1 = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - _sha256 = FingerprintBuilder - .Create(SHA256.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - _sha512 = FingerprintBuilder - .Create(SHA512.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - } + FirstName = "John", + LastName = "Smith" + }; - [Benchmark] - public string MD5_Model_To_Hex() - { - return _md5(_user).ToLowerHexString(); - } - - [Benchmark] - public string SHA1_Model_To_Hex() - { - return _sha1(_user).ToLowerHexString(); - } - - [Benchmark] - public string SHA256_Model_To_Hex() - { - return _sha256(_user).ToLowerHexString(); - } - - [Benchmark] - public string SHA512_Model_To_Hex() - { - return _sha512(_user).ToLowerHexString(); - } + _md5 = FingerprintBuilder + .Create(MD5.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); - private class UserInfo - { - public string FirstName { get; set; } + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + + _sha256 = FingerprintBuilder + .Create(SHA256.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + + _sha512 = FingerprintBuilder + .Create(SHA512.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + } + + [Benchmark] + public string MD5_Model_To_Hex() + { + return _md5(_user).ToLowerHexString(); + } + + [Benchmark] + public string SHA1_Model_To_Hex() + { + return _sha1(_user).ToLowerHexString(); + } + + [Benchmark] + public string SHA256_Model_To_Hex() + { + return _sha256(_user).ToLowerHexString(); + } + + [Benchmark] + public string SHA512_Model_To_Hex() + { + return _sha512(_user).ToLowerHexString(); + } + + private class UserInfo + { + public string FirstName { get; set; } - public string LastName { get; set; } - } + public string LastName { get; set; } } } diff --git a/tests/units/ArrayFingerprintBuilderTests.cs b/tests/units/ArrayFingerprintBuilderTests.cs deleted file mode 100644 index 62524a0..0000000 --- a/tests/units/ArrayFingerprintBuilderTests.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Security.Cryptography; -using Xunit; - -namespace FingerprintBuilder.Tests -{ - public partial class ArrayFingerprintBuilderTests - { - [Fact] - public void UserInfo_Sha1() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.Name) - .For(p => p.Emails) - .Build(); - - var user = new UserInfo - { - Name = "John", - Emails = new[] { "test@test.com", "test1@test.com" } - }; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal("365993bbd89e2e25039848e51904679cc9e13d17", hash); - } - - [Fact] - public void UserInfo_EmailsString_Sha1() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.Name) - .For(p => p.Emails, emails => string.Join('|', emails)) - .Build(); - - var user = new UserInfo - { - Name = "John", - Emails = new[] { "test@test.com", "test1@test.com" } - }; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal("9f825a64a3eb7a7f0b4887ce09ad2a76d085a8b0", hash); - } - - private class UserInfo - { - public string Name { get; set; } - - public string[] Emails { get; set; } - } - } -} diff --git a/tests/units/ExtensionsTests.cs b/tests/units/ExtensionsTests.cs new file mode 100644 index 0000000..0cd6887 --- /dev/null +++ b/tests/units/ExtensionsTests.cs @@ -0,0 +1,27 @@ +using System; +using Xunit; + +namespace FingerprintBuilder.Tests; + +public class ExtensionsTests +{ + [Fact] + public void Bytes_ToLowerHexString() + { + byte[] bytes = { 1, 12 }; + Assert.Equal("010c", bytes.ToLowerHexString()); + } + + [Fact] + public void Bytes_ToUpperHexString() + { + byte[] bytes = { 1, 12 }; + Assert.Equal("010C", bytes.ToUpperHexString()); + } + + [Fact] + public void Bytes_Null_Throw_ArgumentNullException() + { + Assert.Throws(() => ((byte[])null).ToUpperHexString()); + } +} diff --git a/tests/units/FingerprintBuilder.Tests.csproj b/tests/units/FingerprintBuilder.Tests.csproj index db47175..0e96446 100644 --- a/tests/units/FingerprintBuilder.Tests.csproj +++ b/tests/units/FingerprintBuilder.Tests.csproj @@ -1,9 +1,10 @@  - net6.0 + net6.0;net7.0 false true opencover + CS0618 diff --git a/tests/units/Models/User.cs b/tests/units/Models/User.cs new file mode 100644 index 0000000..c5f5721 --- /dev/null +++ b/tests/units/Models/User.cs @@ -0,0 +1,8 @@ +namespace FingerprintBuilder.Tests.Models; + +public class User +{ + public string FirstName { get; set; } + + public string LastName { get; set; } +} diff --git a/tests/units/SimpleFingerprintBuilderTests.cs b/tests/units/SimpleFingerprintBuilderTests.cs deleted file mode 100644 index 45accf1..0000000 --- a/tests/units/SimpleFingerprintBuilderTests.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Security.Cryptography; -using Xunit; -using Xunit.Abstractions; - -namespace FingerprintBuilder.Tests -{ - public class SimpleFingerprintBuilderTests - { - private readonly ITestOutputHelper _testOutputHelper; - - public SimpleFingerprintBuilderTests(ITestOutputHelper testOutputHelper) - { - _testOutputHelper = testOutputHelper; - } - - [Fact] - public void UserInfo_Sha1() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = "Smith" }; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal("bfe2cb034d9448e66f642506e6370dd87bbbe0e0", hash); - } - - [Fact] - public void UserInfo_ToLowerCase_Sha1() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName, true, true) - .For(p => p.LastName, true, true) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = "Smith" }; - - const string expectedHash = "df7fd58e2378573dd2e6e7340a9b2390d2bda770"; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal(expectedHash, hash); - - user.FirstName = user.FirstName.ToLowerInvariant(); - user.LastName = user.LastName.ToLowerInvariant(); - - var hash1 = fingerprint(user).ToLowerHexString(); - Assert.Equal(expectedHash, hash1); - } - - [Fact] - public void UserInfo_Sha256() - { - var fingerprint = FingerprintBuilder - .Create(SHA256.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = "Smith" }; - - var hashLower = fingerprint(user).ToLowerHexString(); - var hashUpper = fingerprint(user).ToUpperHexString(); - - Assert.Equal("9996c4bbc1da4938144886b27b7c680e75932b5a56d911754d75ae4e0a9b4f1a", hashLower); - Assert.Equal("9996c4bbc1da4938144886b27b7c680e75932b5a56d911754d75ae4e0a9b4f1a".ToUpperInvariant(), hashUpper); - } - - [Fact] - public void UserInfo_ToLowerCase_Sha256() - { - var fingerprint = FingerprintBuilder - .Create(SHA256.Create().ComputeHash) - .For(p => p.FirstName, true, true) - .For(p => p.LastName, true, true) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = "Smith" }; - - const string expectedHash = "6012fe3d8bd3038b701c9ddec210b591baecc3aa2ec1f727a7d1f3c9f2032cb3"; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal(expectedHash, hash); - - user.FirstName = user.FirstName.ToLowerInvariant(); - user.LastName = user.LastName.ToLowerInvariant(); - - var hash1 = fingerprint(user).ToLowerHexString(); - Assert.Equal(expectedHash, hash1); - } - - [Fact] - public void UserInfo_Sha1_Null() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = null }; - - var hash = fingerprint(user).ToLowerHexString(); - - Assert.Equal("5ab5aeba11346413348fb7c9361058e016ecf3ca", hash); - } - - [Fact] - public void UserInfo_Sha1_Equals_AnotherUserInfo_Sha1() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName) - .For(p => p.LastName) - .Build(); - - var fingerprintAnother = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.FirstName1) - .For(p => p.LastName1) - .Build(); - - var user = new UserInfo { FirstName = "John", LastName = "Smith" }; - - var hash = fingerprint(new UserInfo { FirstName = "John", LastName = "Smith" }).ToLowerHexString(); - - var hashRevert = fingerprintAnother(new AnotherUserInfo() { LastName1 = "Smith", FirstName1 = "John" }).ToLowerHexString(); - - Assert.Equal(hash, hashRevert); - } - - private class UserInfo - { - public string FirstName { get; set; } - - public string LastName { get; set; } - } - - private class AnotherUserInfo - { - public string LastName1 { get; set; } - - public string FirstName1 { get; set; } - } - } -} diff --git a/tests/units/ThreadSafeFingerprintBuilderTests.cs b/tests/units/ThreadSafeFingerprintBuilderTests.cs deleted file mode 100644 index ca61912..0000000 --- a/tests/units/ThreadSafeFingerprintBuilderTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Security.Cryptography; -using System.Threading.Tasks; -using Xunit; - -namespace FingerprintBuilder.Tests -{ - public class ThreadSafeFingerprintBuilderTests - { - [Fact] - public async Task UserInfo_Sha1_LoopThread() - { - var fingerprint = FingerprintBuilder - .Create(SHA1.Create().ComputeHash) - .For(p => p.Name) - .Build(); - - var tasks = new List(); - for (var p = 0; p < 100; p++) - { - var task = Task.Run(() => - { - for (int i = 0; i < 10000; i++) - { - var hash = fingerprint(new UserInfo { Name = Guid.NewGuid().ToString() }).ToLowerHexString(); - Assert.NotEqual("0000000000000000000000000000000000000000", hash); - } - }); - tasks.Add(task); - } - - await Task.WhenAll(tasks); - } - - private class UserInfo - { - public string Name { get; set; } - } - } -} diff --git a/tests/units/ThreadSafeTests.cs b/tests/units/ThreadSafeTests.cs new file mode 100644 index 0000000..089b609 --- /dev/null +++ b/tests/units/ThreadSafeTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Threading.Tasks; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests; + +public class ThreadSafeTests +{ + [Fact] + public async Task UserInfo_Sha1_LoopThread() + { + var sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .Build(); + + var tasks = new List(); + for (var p = 0; p < 100; p++) + { + var task = Task.Run(() => + { + for (int i = 0; i < 10000; i++) + { + var hash = sha1(new User { FirstName = Guid.NewGuid().ToString() }).ToLowerHexString(); + Assert.NotEqual("0000000000000000000000000000000000000000", hash); + } + }); + tasks.Add(task); + } + + await Task.WhenAll(tasks); + } +} diff --git a/tests/units/TrimToLowerTests.cs b/tests/units/TrimToLowerTests.cs new file mode 100644 index 0000000..b80b1e3 --- /dev/null +++ b/tests/units/TrimToLowerTests.cs @@ -0,0 +1,77 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests; + +public class TrimToLowerTests +{ + private readonly Func _sha1; + + public TrimToLowerTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName, true, true) + .For(p => p.LastName, true, true) + .Build(); + } + + [Fact] + public void Sha1_ToLower_Trim() + { + const string expectedHash = "302ad30676be9e618daed716b3710ab70c1323db"; + + var user = new User { FirstName = "John ", LastName = "Smith " }; + + var hash = _sha1(user).ToLowerHexString(); + + Assert.Equal(expectedHash, hash); + + user.FirstName = user.FirstName.ToLowerInvariant(); + user.LastName = user.LastName.ToLowerInvariant(); + + var hash1 = _sha1(user).ToLowerHexString(); + Assert.Equal(expectedHash, hash1); + } + + [Fact] + public void ToLower_Trim_Null() + { + const string expectedHash = "a4134a2d9c98e1a5dab785714fee4b84c4fcb364"; + var user = new User { FirstName = null, LastName = "Smith " }; + + var hash = _sha1(user).ToLowerHexString(); + + Assert.Equal(expectedHash, hash); + + user.LastName = user.LastName.ToLowerInvariant(); + + var hash1 = _sha1(user).ToLowerHexString(); + Assert.Equal(expectedHash, hash1); + } + + [Fact] + public void Sha256_ToLower_Trim() + { + var sha256 = FingerprintBuilder + .Create(SHA256.Create()) + .For(p => p.FirstName, true, true) + .For(p => p.LastName, true, true) + .Build(); + + const string expectedHash = "fdd11c24f2c3f4cd9e57fbbdf77aa4c3332959fda1f6097a92d6e212aa2a533f"; + var user = new User { FirstName = "John", LastName = "Smith " }; + + var hash = sha256(user).ToLowerHexString(); + + Assert.Equal(expectedHash, hash); + + user.FirstName = user.FirstName.ToLowerInvariant(); + user.LastName = user.LastName.ToLowerInvariant(); + + var hash1 = sha256(user).ToLowerHexString(); + Assert.Equal(expectedHash, hash1); + } +} diff --git a/tests/units/TypedTests/ArrStringTests.cs b/tests/units/TypedTests/ArrStringTests.cs new file mode 100644 index 0000000..b92fe7e --- /dev/null +++ b/tests/units/TypedTests/ArrStringTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class ArrStringTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public ArrStringTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Emails, emails => string.Join('|', emails)) + .Build(); + _user = new ThisUser { FirstName = "John", Emails = new[] { "test@test.com" } }; + } + + [Fact] + public void EmailsAsArray_ThrowArgumentException() + { + var exception = Assert.Throws(() => FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Emails) + .Build()); + Assert.Equal(nameof(ThisUser.Emails), exception.ParamName); + } + + [Fact] + public void Sha1_EmailsToString() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("a9840b53e6aadb3a3a5a48d3ffc9df56441304b6", hash); + } + + [Fact] + public void Sha1_EmailsToString_UpdateArray_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.Emails[0] += "1"; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public string[] Emails { get; set; } + } +} diff --git a/tests/units/TypedTests/BoolTests.cs b/tests/units/TypedTests/BoolTests.cs new file mode 100644 index 0000000..565338d --- /dev/null +++ b/tests/units/TypedTests/BoolTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class BoolTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public BoolTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.IsActive) + .Build(); + + _user = new ThisUser { FirstName = "John", IsActive = true }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("fe563bb6a90707c3e2f9c2960a4c96de7d894762", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateBool_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.IsActive = false; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public bool IsActive { get; set; } + } +} diff --git a/tests/units/TypedTests/ByteTests.cs b/tests/units/TypedTests/ByteTests.cs new file mode 100644 index 0000000..7fda922 --- /dev/null +++ b/tests/units/TypedTests/ByteTests.cs @@ -0,0 +1,75 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class ByteTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public ByteTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.ByteNumber) + .For(p => p.SByteNumber) + .For(p => p.ByteArrNumbers) + .Build(); + + _user = new ThisUser + { + FirstName = "John", + ByteNumber = 2, + SByteNumber = 1, + ByteArrNumbers = new byte[] { 1, 2 } + }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("9bba39dc41a4d896f1a54e0c37fed94a8722189f", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateByte_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.ByteNumber = 3; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + [Fact] + public void UserInfo_Sha1_UpdateSByte_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.SByteNumber = -1; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + [Fact] + public void UserInfo_Sha1_UpdateSByteArray_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.ByteArrNumbers[1] = 5; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public byte ByteNumber { get; set; } + public sbyte SByteNumber { get; set; } + public byte[] ByteArrNumbers { get; set; } + } +} diff --git a/tests/units/TypedTests/CharTests.cs b/tests/units/TypedTests/CharTests.cs new file mode 100644 index 0000000..c5273e4 --- /dev/null +++ b/tests/units/TypedTests/CharTests.cs @@ -0,0 +1,64 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class CharTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public CharTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Char) + .For(p => p.ArrChars) + .Build(); + + _user = new ThisUser + { + FirstName = "John", + Char = 'a', + ArrChars = new[] { 'a', 'b' } + }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("c2969eeda3f16f68058e987e0f0822708837b7a4", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateChar_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.Char = 'c'; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + + [Fact] + public void UserInfo_Sha1_UpdateCharArray_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.ArrChars[1] = 'c'; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public char Char { get; set; } + + public char[] ArrChars { get; set; } + } +} diff --git a/tests/units/TypedTests/DecimalTests.cs b/tests/units/TypedTests/DecimalTests.cs new file mode 100644 index 0000000..eb6ba53 --- /dev/null +++ b/tests/units/TypedTests/DecimalTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class DecimalTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public DecimalTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Number) + .Build(); + + _user = new ThisUser { FirstName = "John", Number = 2.1m }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("0e9124882db525d318aaad3047f579978f5b0fbb", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateBool_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.Number = 2.11m; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public decimal Number { get; set; } + } +} diff --git a/tests/units/TypedTests/DoubleTests.cs b/tests/units/TypedTests/DoubleTests.cs new file mode 100644 index 0000000..6fc1154 --- /dev/null +++ b/tests/units/TypedTests/DoubleTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class DoubleTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public DoubleTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Number) + .Build(); + + _user = new ThisUser { FirstName = "John", Number = 2.1d }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("af167d0996599a29b89ce1c467013bb7c98e7dcb", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateBool_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.Number = 2.11d; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public double Number { get; set; } + } +} diff --git a/tests/units/TypedTests/FloatTests.cs b/tests/units/TypedTests/FloatTests.cs new file mode 100644 index 0000000..e45b619 --- /dev/null +++ b/tests/units/TypedTests/FloatTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class FloatTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public FloatTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Number) + .Build(); + + _user = new ThisUser { FirstName = "John", Number = 2.1f }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("487b230857d43f392b9d20189d972d0cc8aa7c98", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateBool_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.Number = 2.11f; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public float Number { get; set; } + } +} diff --git a/tests/units/TypedTests/HalfTests.cs b/tests/units/TypedTests/HalfTests.cs new file mode 100644 index 0000000..c44c23f --- /dev/null +++ b/tests/units/TypedTests/HalfTests.cs @@ -0,0 +1,26 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class HalfTests +{ + [Fact] + public void Half_ThrowArgumentException() // Half is not avalaivable in 'netstandard2.*' + { + var exception = Assert.Throws(() => FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.Number) + .Build()); + + Assert.Equal(nameof(ThisUser.Number), exception.ParamName); + } + + private class ThisUser : User + { + public Half Number { get; set; } + } +} diff --git a/tests/units/TypedTests/IntTests.cs b/tests/units/TypedTests/IntTests.cs new file mode 100644 index 0000000..fdfaf76 --- /dev/null +++ b/tests/units/TypedTests/IntTests.cs @@ -0,0 +1,62 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class IntTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public IntTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.IntNumber) + .For(p => p.UIntNumber) + .Build(); + + _user = new ThisUser + { + FirstName = "John", + IntNumber = -2, + UIntNumber = 2, + }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("8670e727f763004645ffb82b49e405b486732b7b", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateShort_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.IntNumber = 2; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + [Fact] + public void UserInfo_Sha1_UpdateUShort_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.UIntNumber = 1; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public int IntNumber { get; set; } + public uint UIntNumber { get; set; } + } +} diff --git a/tests/units/TypedTests/LongTests.cs b/tests/units/TypedTests/LongTests.cs new file mode 100644 index 0000000..dc90b12 --- /dev/null +++ b/tests/units/TypedTests/LongTests.cs @@ -0,0 +1,62 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class LongTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public LongTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.LongNumber) + .For(p => p.ULongNumber) + .Build(); + + _user = new ThisUser + { + FirstName = "John", + LongNumber = -2, + ULongNumber = 2, + }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("f6b0bac504d0d966b2b1ea2e0504f2ee661f0d40", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateLong_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.LongNumber = 2; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + [Fact] + public void UserInfo_Sha1_UpdateULong_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.ULongNumber = 1; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public long LongNumber { get; set; } + public ulong ULongNumber { get; set; } + } +} diff --git a/tests/units/TypedTests/ShortTests.cs b/tests/units/TypedTests/ShortTests.cs new file mode 100644 index 0000000..d31cbb4 --- /dev/null +++ b/tests/units/TypedTests/ShortTests.cs @@ -0,0 +1,62 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class ShortTests +{ + private readonly Func _sha1; + private readonly ThisUser _user; + + public ShortTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.ShortNumber) + .For(p => p.UShortNumber) + .Build(); + + _user = new ThisUser + { + FirstName = "John", + ShortNumber = -2, + UShortNumber = 2, + }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + Assert.Equal("3c6cd62c0c7ca868fabfd931a9ca4bdb39cc804f", hash); + } + + [Fact] + public void UserInfo_Sha1_UpdateShort_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.ShortNumber = 2; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + [Fact] + public void UserInfo_Sha1_UpdateUShort_ChangeHash() + { + var hash0 = _sha1(_user).ToLowerHexString(); + _user.UShortNumber = 1; + var hash1 = _sha1(_user).ToLowerHexString(); + + Assert.NotEqual(hash0, hash1); + } + + private class ThisUser : User + { + public short ShortNumber { get; set; } + public ushort UShortNumber { get; set; } + } +} diff --git a/tests/units/TypedTests/StringTests.cs b/tests/units/TypedTests/StringTests.cs new file mode 100644 index 0000000..1a56af1 --- /dev/null +++ b/tests/units/TypedTests/StringTests.cs @@ -0,0 +1,100 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests.TypedTests; + +public class StringTests +{ + private readonly Func _sha1; + private readonly User _user; + + public StringTests() + { + _sha1 = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + _user = new User { FirstName = "John", LastName = "Smith" }; + } + + [Fact] + public void Sha1() + { + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("ac1992c8791c6ae5c8a2e8ed22feb109d86dc091", hash); + } + + [Fact] + public void Sha256() + { + var sha256 = FingerprintBuilder + .Create(SHA256.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + + var hashLower = sha256(_user).ToLowerHexString(); + var hashUpper = sha256(_user).ToUpperHexString(); + + const string expected = "62565a67bf16004038c502eb68907411fcf7871c66ee01a1aa274cc18d9fb541"; + + Assert.Equal(expected, hashLower); + Assert.Equal(expected.ToUpperInvariant(), hashUpper); + } + + + [Fact] + public void Sha1_Null() + { + _user.LastName = null; + + var hash = _sha1(_user).ToLowerHexString(); + + Assert.Equal("2e2a2813f314668223c79f0bc819b39ce71810ca", hash); + } + + [Fact] + public void Sha1_Equals_AnotherBaseUser_Sha1() + { + var sha1ChangedProp = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName1) + .For(p => p.LastName1) + .Build(); + + var hash = _sha1(_user).ToLowerHexString(); + + var hashChangedProp = sha1ChangedProp(new ChangedPropUser { LastName1 = "Smith", FirstName1 = "John" }).ToLowerHexString(); + + Assert.Equal(hash, hashChangedProp); + } + + [Fact] + public void Sha1_Compare_Create() + { + var sha1A = FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + + var sha1B = FingerprintBuilder + .Create(SHA1.Create().ComputeHash) + .For(p => p.FirstName) + .For(p => p.LastName) + .Build(); + + Assert.Equal(sha1A(_user).ToLowerHexString(), sha1B(_user).ToLowerHexString()); + } + + private class ChangedPropUser + { + public string LastName1 { get; set; } + + public string FirstName1 { get; set; } + } +} diff --git a/tests/units/WrongBuildTests.cs b/tests/units/WrongBuildTests.cs new file mode 100644 index 0000000..e6680c0 --- /dev/null +++ b/tests/units/WrongBuildTests.cs @@ -0,0 +1,40 @@ +using System; +using System.Security.Cryptography; +using FingerprintBuilder.Tests.Models; +using Xunit; + +namespace FingerprintBuilder.Tests; + +public class WrongBuildTests +{ + [Fact] + public void ComputeHash_Null_Throw_ArgumentNullException() + { + Assert.Throws(() => FingerprintBuilder.Create(computeHash: null)); + } + + [Fact] + public void HashAlgorithm_Null_Throw_ArgumentException() + { + Assert.Throws(() => FingerprintBuilder.Create(hashAlgorithm: null)); + } + + [Fact] + public void For_Prop_Duplicate_Throw_ArgumentException() + { + var exception = Assert.Throws(() => FingerprintBuilder + .Create(SHA1.Create()) + .For(p => p.FirstName) + .For(p => p.FirstName)); + + Assert.Equal(nameof(User.FirstName), exception.ParamName); + } + + [Fact] + public void For_Prop_IsNot_MemberExpression_Throw_ArgumentException() + { + Assert.Throws(() => FingerprintBuilder + .Create(SHA1.Create()) + .For(p => "")); + } +}