diff --git a/README.md b/README.md index f44a3c2..f560ce4 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ | **Xtz.StornglyTyped.BuiltinTypes.AutoFixture** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.BuiltinTypes.AutoFixture.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/) | | **Xtz.StornglyTyped.BuiltinTypes.Bogus** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.BuiltinTypes.Bogus.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.BuiltinTypes.Bogus/) | | **Xtz.StornglyTyped.EntityFramework** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.EntityFramework.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.EntityFramework/) | +| **Xtz.StronglyTyped.NewtonsoftJson** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.NewtonsoftJson.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.NewtonsoftJson/) | | **Xtz.StornglyTyped.SourceGenerator** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.SourceGenerator.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.SourceGenerator/) | | **Xtz.StornglyTyped.Swashbuckle** | [![NuGet](http://img.shields.io/nuget/v/Xtz.StronglyTyped.Swashbuckle.svg)](https://www.nuget.org/packages/Xtz.StronglyTyped.Swashbuckle/) | diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..451d6da --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# RCS1124: Inline local variable. +dotnet_diagnostic.RCS1124.severity = none diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/GlobalSuppressions.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/GlobalSuppressions.cs new file mode 100644 index 0000000..24d3acb --- /dev/null +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Major Code Smell", "S1854:Unused assignments should be removed", Justification = "Vlad DX: Reviewed. It's intentional", Scope = "member", Target = "~M:Xtz.StronglyTyped.Benchmark.Program.Main()")] diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/Models/IntStructId.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/Models/IntStructId.cs index f4f10a9..8897d0e 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/Models/IntStructId.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/Models/IntStructId.cs @@ -8,7 +8,7 @@ public partial struct IntStructId private bool IsValid(int value) { // ID must be greater than 0 - return value <= 0; + return value > 0; } } } \ No newline at end of file diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/Program.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/Program.cs index afa19ab..62dea7b 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/Program.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/Program.cs @@ -3,12 +3,13 @@ namespace Xtz.StronglyTyped.Benchmark { - public class Program + public static class Program { public const int VALUE_COUNT = 1000; - public static void Main(string[] args) + public static void Main() { + // ReSharper disable once RedundantAssignment var config = DefaultConfig.Instance; #if DEBUG @@ -16,9 +17,9 @@ public static void Main(string[] args) #endif BenchmarkRunner.Run(config); - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); + BenchmarkRunner.Run(config); + BenchmarkRunner.Run(config); + BenchmarkRunner.Run(config); } } } \ No newline at end of file diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationEmails.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationEmails.cs index 933ed48..07c8aba 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationEmails.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationEmails.cs @@ -24,7 +24,7 @@ public SystemTextJsonSerializationEmails() { ////System.Diagnostics.Debugger.Launch(); - var fakerBuilder = new InternetFakerBuilder(true); + var fakerBuilder = new InternetFakerBuilder(); var faker = fakerBuilder.BuildEmailFaker(); _emails = faker.Generate(Program.VALUE_COUNT).ToArray(); diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationGuidIds.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationGuidIds.cs index 5c12fb1..fbacebb 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationGuidIds.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationGuidIds.cs @@ -10,8 +10,6 @@ namespace Xtz.StronglyTyped.Benchmark [MemoryDiagnoser] public class SystemTextJsonSerializationGuidIds { - private readonly Faker _faker; - private readonly EmployeeGuidId[] _employeeGuidIds; private readonly EmployeeGuidId[] _otherEmployeeGuidIds; @@ -22,10 +20,10 @@ public class SystemTextJsonSerializationGuidIds public SystemTextJsonSerializationGuidIds() { - _faker = new Faker(); + var faker = new Faker(); - _employeeGuidIds = _faker.Generate(Program.VALUE_COUNT).ToArray(); - _otherEmployeeGuidIds = _faker.Generate(Program.VALUE_COUNT).ToArray(); + _employeeGuidIds = faker.Generate(Program.VALUE_COUNT).ToArray(); + _otherEmployeeGuidIds = faker.Generate(Program.VALUE_COUNT).ToArray(); _guids = _employeeGuidIds.Select(x => x.Value).ToArray(); _stronglyTypedGuidStructs = _employeeGuidIds.Select(x => (GuidStructId)x.Value).ToArray(); } @@ -38,21 +36,21 @@ public string SerializeEmailStrings() } [Benchmark(Description = "StronglyTyped>")] - public string SerializeStronglyTypedStringStructs() + public string SerializeStronglyTypedGuidStructs() { var result = JsonSerializer.Serialize(_stronglyTypedGuidStructs); return result; } [Benchmark(Description = "StronglyTyped")] - public string SerializeStronglyTypedEmails() + public string SerializeStronglyTypedGuids() { var result = JsonSerializer.Serialize(_employeeGuidIds); return result; } [Benchmark(Description = "Other StronglyTyped")] - public string SerializeOtherStronglyTypedEmails() + public string SerializeOtherStronglyTypedGuids() { var result = JsonSerializer.Serialize(_otherEmployeeGuidIds); return result; diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationIntIds.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationIntIds.cs index f3ad3ff..303b605 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationIntIds.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationIntIds.cs @@ -10,8 +10,6 @@ namespace Xtz.StronglyTyped.Benchmark [MemoryDiagnoser] public class SystemTextJsonSerializationIntIds { - private readonly Faker _faker; - private readonly CompanyIntId[] _companyIntIds; private readonly CompanyIntId[] _otherCompanyIntIds; @@ -22,38 +20,38 @@ public class SystemTextJsonSerializationIntIds public SystemTextJsonSerializationIntIds() { - _faker = new Faker() + var faker = new Faker() .CustomInstantiator(f => new CompanyIntId(Math.Abs(f.Random.Int()))); - _companyIntIds = _faker.Generate(Program.VALUE_COUNT).ToArray(); - _otherCompanyIntIds = _faker.Generate(Program.VALUE_COUNT).ToArray(); + _companyIntIds = faker.Generate(Program.VALUE_COUNT).ToArray(); + _otherCompanyIntIds = faker.Generate(Program.VALUE_COUNT).ToArray(); _ints = _companyIntIds.Select(x => x.Value).ToArray(); _stronglyTypedIntStructs = _companyIntIds.Select(x => (IntStructId)x.Value).ToArray(); } [Benchmark(Baseline = true, Description = "int")] - public string SerializeEmailStrings() + public string SerializeInts() { var result = JsonSerializer.Serialize(_ints); return result; } [Benchmark(Description = "StronglyTyped>")] - public string SerializeStronglyTypedStringStructs() + public string SerializeStronglyTypedIntStructs() { var result = JsonSerializer.Serialize(_stronglyTypedIntStructs); return result; } [Benchmark(Description = "StronglyTyped")] - public string SerializeStronglyTypedEmails() + public string SerializeStronglyTypedIntIds() { var result = JsonSerializer.Serialize(_companyIntIds); return result; } [Benchmark(Description = "Other StronglyTyped")] - public string SerializeOtherStronglyTypedEmails() + public string SerializeOtherStronglyTypedIntIds() { var result = JsonSerializer.Serialize(_otherCompanyIntIds); return result; diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationMacAddress.cs b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationMacAddress.cs index 501d693..3885dd1 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationMacAddress.cs +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/SystemTextJsonSerializationMacAddress.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Text.Json; using BenchmarkDotNet.Attributes; -using Bogus; using Xtz.StronglyTyped.Benchmark.Models; using Xtz.StronglyTyped.BuiltinTypes.Bogus; using Xtz.StronglyTyped.BuiltinTypes.Internet; @@ -11,10 +10,6 @@ namespace Xtz.StronglyTyped.Benchmark [MemoryDiagnoser] public class SystemTextJsonSerializationMacAddress { - private readonly InternetFakerBuilder _fakerBuilder; - - private readonly Faker _faker; - private readonly MacAddress[] _macAddresses; private readonly MacAddress[] _otherMacAddresses; @@ -27,11 +22,11 @@ public class SystemTextJsonSerializationMacAddress public SystemTextJsonSerializationMacAddress() { - _fakerBuilder = new InternetFakerBuilder(true); - _faker = _fakerBuilder.BuildMacAddressFaker(); + var fakerBuilder = new InternetFakerBuilder(); + var faker = fakerBuilder.BuildMacAddressFaker(); - _macAddresses = _faker.Generate(Program.VALUE_COUNT).ToArray(); - _otherMacAddresses = _faker.Generate(Program.VALUE_COUNT).ToArray(); + _macAddresses = faker.Generate(Program.VALUE_COUNT).ToArray(); + _otherMacAddresses = faker.Generate(Program.VALUE_COUNT).ToArray(); _strings = _macAddresses.Select(x => x.ToString()).ToArray(); _stronglyTypedStrings = _strings.Select(x => (StronglyTypedString)x).ToArray(); _stronglyTypedStructs = _strings.Select(x => (StronglyTypedStringStruct)x).ToArray(); @@ -40,7 +35,7 @@ public SystemTextJsonSerializationMacAddress() } [Benchmark(Baseline = true, Description = "string")] - public string SerializeEmailStrings() + public string SerializeMacAddressStrings() { var result = JsonSerializer.Serialize(_strings); return result; @@ -60,15 +55,15 @@ public string SerializeStronglyTypedStringStructs() return result; } - [Benchmark(Description = "StronglyTyped")] - public string SerializeStronglyTypedEmails() + [Benchmark(Description = "StronglyTyped")] + public string SerializeStronglyTypedMacAddresses() { var result = JsonSerializer.Serialize(_macAddresses); return result; } - [Benchmark(Description = "Other StronglyTyped")] - public string SerializeOtherStronglyTypedEmails() + [Benchmark(Description = "Other StronglyTyped")] + public string SerializeOtherStronglyTypedMacAddresses() { var result = JsonSerializer.Serialize(_otherMacAddresses); return result; diff --git a/src/Misc/Xtz.StronglyTyped.Benchmark/Xtz.StronglyTyped.Benchmark.csproj b/src/Misc/Xtz.StronglyTyped.Benchmark/Xtz.StronglyTyped.Benchmark.csproj index 6557977..f46585b 100644 --- a/src/Misc/Xtz.StronglyTyped.Benchmark/Xtz.StronglyTyped.Benchmark.csproj +++ b/src/Misc/Xtz.StronglyTyped.Benchmark/Xtz.StronglyTyped.Benchmark.csproj @@ -2,7 +2,7 @@ Exe - net5 + netstandard2.1 @@ -12,21 +12,24 @@ - - - - - - - - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/src/Misc/Xtz.StronglyTyped.Playground/Program.cs b/src/Misc/Xtz.StronglyTyped.Playground/Program.cs index 0309950..f26bf19 100644 --- a/src/Misc/Xtz.StronglyTyped.Playground/Program.cs +++ b/src/Misc/Xtz.StronglyTyped.Playground/Program.cs @@ -5,7 +5,7 @@ namespace Xtz.StronglyTyped.Playground { // NOTE: Just a simple console app for demo purposes - public class Program + public static class Program { public static void Main() { @@ -25,7 +25,7 @@ public static void Main() private static void RunAddressFakers() { - var fakerBuilder = new AddressFakerBuilder(true); + var fakerBuilder = new AddressFakerBuilder(); var city = fakerBuilder.BuildCityFaker().Generate(); Console.WriteLine(city); @@ -72,7 +72,7 @@ private static void RunAddressFakers() private static void RunInternetFakers() { - var fakerBuilder = new InternetFakerBuilder(true); + var fakerBuilder = new InternetFakerBuilder(); var absoluteUri = fakerBuilder.BuildAbsoluteUriFaker().Generate(); Console.WriteLine(absoluteUri); diff --git a/src/Misc/Xtz.StronglyTyped.Playground/Xtz.StronglyTyped.Playground.csproj b/src/Misc/Xtz.StronglyTyped.Playground/Xtz.StronglyTyped.Playground.csproj index 65cfcba..2582ab7 100644 --- a/src/Misc/Xtz.StronglyTyped.Playground/Xtz.StronglyTyped.Playground.csproj +++ b/src/Misc/Xtz.StronglyTyped.Playground/Xtz.StronglyTyped.Playground.csproj @@ -16,26 +16,27 @@ - - false - - True $(BaseIntermediateOutputPath)\GeneratedFiles - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -44,11 +45,4 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/GlobalSuppressions.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/GlobalSuppressions.cs new file mode 100644 index 0000000..b7c13d2 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/GlobalSuppressions.cs @@ -0,0 +1,12 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S1481:Unused local variables should be removed", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApiTests.ShouldDeserialize_ForStandardEndpoint_WhenNewtonsoftUsed~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Minor Code Smell", "S1481:Unused local variables should be removed", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApiTests.ShouldDeserialize_ForStandardEndpoint_WhenSystemTextJsonUsed~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Minor Code Smell", "S1481:Unused local variables should be removed", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApiTests.ShouldDeserialize_ForStronglyTypedEndpoint_WhenNewtonsoftUsed~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Minor Code Smell", "S1481:Unused local variables should be removed", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApiTests.ShouldDeserialize_ForStronglyTypedEndpoint_WhenSystemTextJsonUsed~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Style", "IDE0059:Unnecessary assignment of a value", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApiTests.ShouldDeserialize_ForStandardEndpoint_WhenNewtonsoftUsed~System.Threading.Tasks.Task")] diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/DegreesCelsius.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/DegreesCelsius.cs similarity index 100% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/DegreesCelsius.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/DegreesCelsius.cs diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs similarity index 96% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs index 8c5503c..1533d7b 100644 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Xtz.StronglyTyped.NewtonsoftJson; namespace Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApi { diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs similarity index 90% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs index 4c16a59..193f089 100644 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedWeatherForecast.cs @@ -7,6 +7,8 @@ public class StronglyTypedWeatherForecast { public City City { get; set; } + public Country NullValue { get; set; } + public DateTime Date { get; set; } public DegreesCelsius TemperatureC { get; set; } diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecast.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecast.cs similarity index 100% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecast.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecast.cs diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs similarity index 75% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs index 0f91c35..3060c00 100644 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WeatherForecastController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; using Xtz.StronglyTyped.BuiltinTypes.Address; namespace Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApi @@ -11,18 +10,11 @@ namespace Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApi [Route("[controller]")] public class WeatherForecastController : ControllerBase { - private static readonly string[] Summaries = new[] + private static readonly string[] SUMMARIES = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - [HttpGet] public IEnumerable Get() { @@ -31,7 +23,7 @@ public IEnumerable Get() { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), - Summary = Summaries[rng.Next(Summaries.Length)] + Summary = SUMMARIES[rng.Next(SUMMARIES.Length)] }) .ToArray(); } @@ -46,7 +38,7 @@ public IEnumerable StronglyTypedGet() City = new City("Amsterdam"), Date = DateTime.Now.AddDays(index), TemperatureC = (DegreesCelsius)rng.Next(-20, 55), - Summary = Summaries[rng.Next(Summaries.Length)] + Summary = SUMMARIES[rng.Next(SUMMARIES.Length)] }) .ToArray(); } diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WebApiFactory.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WebApiFactory.cs similarity index 100% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WebApiFactory.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/WebApiFactory.cs diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs similarity index 64% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs index b30d14a..617c704 100644 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApiTests.cs @@ -5,18 +5,26 @@ using Newtonsoft.Json; using NUnit.Framework; using Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApi; +using Xtz.StronglyTyped.BuiltinTypes.Address; +using Xtz.StronglyTyped.NewtonsoftJson; namespace Xtz.StronglyTyped.Api_3_1.IntegrationTests { - public class WebApiTests : IDisposable + public sealed class WebApiTests : IDisposable { + private readonly JsonSerializerSettings _jsonSerializerSettings; + private readonly WebApiFactory _factory = new(); - + private readonly HttpClient _client; public WebApiTests() { _client = _factory.CreateClient(); + + var jsonSerializerSettings = new JsonSerializerSettings(); + jsonSerializerSettings.Converters.Add(new StronglyTypedNewtonsoftConverter()); + _jsonSerializerSettings = jsonSerializerSettings; } [Test] @@ -27,7 +35,7 @@ public async Task ShouldReturn200_ForStandardEndpoint() // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); } [Test] @@ -38,10 +46,14 @@ public async Task ShouldDeserialize_ForStandardEndpoint_WhenNewtonsoftUsed() // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); + + Country country = null; + // ReSharper disable once ExpressionIsAlwaysNull + var _ = JsonConvert.SerializeObject(country); var responseStr = await response.Content.ReadAsStringAsync(); - var responseObject = JsonConvert.DeserializeObject>(responseStr); + var __ = JsonConvert.DeserializeObject>(responseStr, _jsonSerializerSettings); } [Test] @@ -52,10 +64,10 @@ public async Task ShouldDeserialize_ForStandardEndpoint_WhenSystemTextJsonUsed() // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); var responseStr = await response.Content.ReadAsStringAsync(); - var responseObject = System.Text.Json.JsonSerializer.Deserialize>(responseStr); + var _ = System.Text.Json.JsonSerializer.Deserialize>(responseStr); } [Test] @@ -66,7 +78,7 @@ public async Task ShouldReturn200_ForStronglyTypedEndpoint() // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); } [Test] @@ -77,10 +89,10 @@ public async Task ShouldDeserialize_ForStronglyTypedEndpoint_WhenNewtonsoftUsed( // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); var responseStr = await response.Content.ReadAsStringAsync(); - var responseObject = JsonConvert.DeserializeObject>(responseStr); + var _ = JsonConvert.DeserializeObject>(responseStr, _jsonSerializerSettings); } [Test] @@ -91,10 +103,10 @@ public async Task ShouldDeserialize_ForStronglyTypedEndpoint_WhenSystemTextJsonU // Assert response.EnsureSuccessStatusCode(); - Assert.NotNull(response.Content); + Assert.That(response.Content, Is.Not.Null); var responseStr = await response.Content.ReadAsStringAsync(); - var responseObject = System.Text.Json.JsonSerializer.Deserialize>(responseStr); + var _ = System.Text.Json.JsonSerializer.Deserialize>(responseStr); } public void Dispose() diff --git a/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj new file mode 100644 index 0000000..0958b98 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj @@ -0,0 +1,45 @@ + + + + netcoreapp3.1 + 9 + + + + true + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/_RecordHack.cs b/src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/_RecordHack.cs similarity index 100% rename from src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/_RecordHack.cs rename to src/Tests/Xtz.StronglyTyped.Api_3_1.IntegrationTests/_RecordHack.cs diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/AddressAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/AddressAutoDataTests.cs index 2ddd3bb..5a7fb0a 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/AddressAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/AddressAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.Address; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; @@ -44,10 +43,7 @@ public void ShouldGenerateStronglyTypedValues( postalCode, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CommerceAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CommerceAutoDataTests.cs index e4c0ee8..2f20f4f 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CommerceAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CommerceAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Commerce; @@ -14,13 +13,11 @@ public void ShouldGenerateStronglyTypedValues( Department department, Ean13 ean13, Ean8 ean8, - Price price, ProductShortName productShortName, ProductAdjective productAdjective, ProductCategory productCategory, ProductColor productColor, ProductMaterial productMaterial, - ProductFullName productFullName, SubDepartment subDepartment) { var values = new object[] @@ -28,20 +25,33 @@ public void ShouldGenerateStronglyTypedValues( department, ean13, ean8, - price, productShortName, productAdjective, productCategory, productColor, productMaterial, - productFullName, subDepartment, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); + } - Assert.IsEmpty(nonBogusValues); + [Test] + [StrongAutoData] + public void ShouldGenerateStronglyTypedPrice(Price value) + { + Assert.That(value.Currency.Code.ToString().IsBogusGeneratedValue(), Is.False); + Assert.That(value.Currency.Name.ToString().IsBogusGeneratedValue(), Is.False); + Assert.That(value.Currency.Symbol?.ToString().IsBogusGeneratedValue(), Is.False); + } + + [Test] + [StrongAutoData] + public void ShouldGenerateStronglyTypedProductFullName(ProductFullName value) + { + Assert.That(value.ProductAdjective.ToString().IsBogusGeneratedValue(), Is.False); + Assert.That(value.ProductMaterial.ToString().IsBogusGeneratedValue(), Is.False); + Assert.That(value.ProductShortName.ToString().IsBogusGeneratedValue(), Is.False); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CompanyAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CompanyAutoDataTests.cs index 799f2b9..7c00182 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CompanyAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/CompanyAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Company; @@ -38,10 +37,7 @@ public void ShouldGenerateStronglyTypedValues( siteCode }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Extensions/Extensions.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Extensions/Extensions.cs new file mode 100644 index 0000000..5e07a8b --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Extensions/Extensions.cs @@ -0,0 +1,15 @@ +using System.Text.RegularExpressions; + +namespace Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions +{ + public static class Extensions + { + /// value0edafc90-698d-4804-9267-3c5e73f4aa94 + private static readonly Regex BOGUS_VALUE_REGEX = new Regex("value[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public static bool IsBogusGeneratedValue(this string value) + { + return BOGUS_VALUE_REGEX.IsMatch(value); + } + } +} diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/FinanceAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/FinanceAutoDataTests.cs index f3ff94f..1432370 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/FinanceAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/FinanceAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Finance; @@ -32,10 +31,7 @@ public void ShouldGenerateStronglyTypedValues( transactionType, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/GlobalSuppressions.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/GlobalSuppressions.cs new file mode 100644 index 0000000..d69ff69 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Major Code Smell", "S4144:Methods should not have identical implementations", Justification = "Vlad DX: Reviewed. It's intentional", Scope = "member", Target = "~M:Xtz.StronglyTyped.BogusAutoFixture.UnitTests.IdAutoDataTests.ShouldGenerateStronglyTypedValues_WithCustomSpecimen(UnitTests.EmployeeGuidId,UnitTests.EmployeeIntId)")] diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/IdAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/IdAutoDataTests.cs index c228714..fe98c5a 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/IdAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/IdAutoDataTests.cs @@ -14,8 +14,8 @@ public void ShouldGenerateStronglyTypedValues( EmployeeGuidId employeeGuidId, EmployeeIntId employeeIntId) { - Assert.AreNotEqual(default(Guid), employeeGuidId?.Value); - Assert.AreNotEqual(default(int), employeeIntId?.Value); + Assert.That(employeeGuidId.Value, Is.Not.EqualTo(default(Guid))); + Assert.That(employeeIntId.Value, Is.Not.EqualTo(default(int))); } [Test] @@ -24,8 +24,8 @@ public void ShouldGenerateStronglyTypedValues_WithCustomSpecimen( EmployeeGuidId employeeGuidId, EmployeeIntId employeeIntId) { - Assert.AreNotEqual(default(Guid), employeeGuidId?.Value); - Assert.AreNotEqual(default(int), employeeIntId?.Value); + Assert.That(employeeGuidId.Value, Is.Not.EqualTo(default(Guid))); + Assert.That(employeeIntId.Value, Is.Not.EqualTo(default(int))); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/InternetAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/InternetAutoDataTests.cs index b59f1cf..8fd7b75 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/InternetAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/InternetAutoDataTests.cs @@ -1,6 +1,6 @@ -using System; -using System.Linq; +using System.Collections.Generic; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Internet; @@ -44,10 +44,14 @@ public void ShouldGenerateStronglyTypedValues( websiteProtocol, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); + } - Assert.IsEmpty(nonBogusValues); + [Test] + [StrongAutoData] + public void ShouldGenerateStronglyTypedCollection(IEnumerable values) + { + Assert.That(values, Is.Not.Empty); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NameAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NameAutoDataTests.cs index 3a3415b..786506e 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NameAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NameAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Name; @@ -13,7 +12,6 @@ public class NameAutoDataTests public void ShouldGenerateStronglyTypedValues( DisplayName displayName, FirstName firstName, - FullName fullName, LastName lastName, NamePrefix namePrefix, NameSuffix nameSuffix) @@ -22,16 +20,19 @@ public void ShouldGenerateStronglyTypedValues( { displayName, firstName, - fullName, lastName, namePrefix, nameSuffix, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); + } - Assert.IsEmpty(nonBogusValues); + [Test] + [StrongAutoData] + public void ShouldGenerateStronglyTypedFullName(FullName value) + { + Assert.That(value.FirstName.ToString()!.IsBogusGeneratedValue(), Is.False); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NumberAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NumberAutoDataTests.cs index 97f4e1e..49baca9 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NumberAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/NumberAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Numbers; @@ -40,10 +39,7 @@ public void ShouldGenerateStronglyTypedValues( positiveInt64, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse((string?) x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/PhoneAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/PhoneAutoDataTests.cs index 7a59f94..4da26eb 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/PhoneAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/PhoneAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Phone; @@ -18,10 +17,7 @@ public void ShouldGenerateStronglyTypedValues( phoneNumber, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/VehicleAutoDataTests.cs b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/VehicleAutoDataTests.cs index 8e71c81..f231d9f 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/VehicleAutoDataTests.cs +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/VehicleAutoDataTests.cs @@ -1,6 +1,5 @@ -using System; -using System.Linq; using NUnit.Framework; +using Xtz.StronglyTyped.BogusAutoFixture.UnitTests.Extensions; using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; using Xtz.StronglyTyped.BuiltinTypes.Vehicle; @@ -26,10 +25,7 @@ public void ShouldGenerateStronglyTypedValues( vin, }; - var nonBogusValues = values - .Where(x => x.ToString()!.Length >= 36 && Guid.TryParse(x.ToString()![^36..], out _)); - - Assert.IsEmpty(nonBogusValues); + Assert.That(values, Is.All.Matches(x => !x.ToString()!.IsBogusGeneratedValue())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests.csproj b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests.csproj index 14bd2bf..8d85df5 100644 --- a/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests.csproj +++ b/src/Tests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests/Xtz.StronglyTyped.BogusAutoFixture.UnitTests.csproj @@ -11,9 +11,26 @@ + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/DbContextTests.cs b/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/DbContextTests.cs index 6229250..2a6de3f 100644 --- a/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/DbContextTests.cs +++ b/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/DbContextTests.cs @@ -1,10 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using Bogus; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using Xtz.StronglyTyped.BuiltinTypes.Address; @@ -18,8 +16,6 @@ namespace Xtz.StronglyTyped.EntityFramework.IntegrationTests { public class DbContextTests { - private readonly ServiceProvider _serviceProvider; - private readonly AppDbContext _dbContext; public DbContextTests() @@ -27,8 +23,8 @@ public DbContextTests() var services = new ServiceCollection(); services.AddDbContext(options => options.UseInMemoryDatabase(GetType().Namespace!)); - _serviceProvider = services.BuildServiceProvider(); - _dbContext = _serviceProvider.GetRequiredService(); + var serviceProvider = services.BuildServiceProvider(); + _dbContext = serviceProvider.GetRequiredService(); } [SetUp] @@ -63,7 +59,7 @@ public void ShouldSucceed_SeedingData_ForGuidId(IReadOnlyCollection cityNa // Assert - Assert.AreEqual(cityNames.Count, cities.Length); + Assert.That(cities.Length, Is.EqualTo(cityNames.Count)); } [Test] @@ -104,8 +100,8 @@ public void ShouldSucceed_SeedingData_ForRelatedData(IReadOnlyCollection c // Assert - Assert.AreEqual(cityNames.Count, cities.Length); - Assert.AreEqual(weatherForecastEntities.Length, weatherForecasts.Length); + Assert.That(cities.Length, Is.EqualTo(cityNames.Count)); + Assert.That(weatherForecasts.Length, Is.EqualTo(weatherForecastEntities.Length)); } [Test] @@ -139,7 +135,7 @@ public void ShouldSucceed_SeedingData_ForStructId() // Assert - Assert.AreEqual(entities.Length, employees.Length); + Assert.That(employees.Length, Is.EqualTo(entities.Length)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/Xtz.StronglyTyped.EntityFramework.IntegrationTests.csproj b/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/Xtz.StronglyTyped.EntityFramework.IntegrationTests.csproj index 8375fe5..c0ab62c 100644 --- a/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/Xtz.StronglyTyped.EntityFramework.IntegrationTests.csproj +++ b/src/Tests/Xtz.StronglyTyped.EntityFramework.IntegrationTests/Xtz.StronglyTyped.EntityFramework.IntegrationTests.csproj @@ -2,17 +2,27 @@ net5.0 - - false - - - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -20,9 +30,6 @@ - - - diff --git a/src/Tests/Xtz.StronglyTyped.IntegrationTests/ConfigurationTests.cs b/src/Tests/Xtz.StronglyTyped.IntegrationTests/ConfigurationTests.cs index e445475..7f737ce 100644 --- a/src/Tests/Xtz.StronglyTyped.IntegrationTests/ConfigurationTests.cs +++ b/src/Tests/Xtz.StronglyTyped.IntegrationTests/ConfigurationTests.cs @@ -23,8 +23,9 @@ public void ShouldNotFail_WhenBindingFromAppSettingsJson() configuration.Bind("Xtz.Test", settings); // Assert - + // Shouldn't fail + Assert.That(settings.Country, Is.Not.Null); } [Test] @@ -44,8 +45,8 @@ public void ShouldBindSection_GivenAppSettingsJson() // Assert - Assert.NotNull(settings); - Assert.AreEqual(expectedCountry, settings.Country); + Assert.That(settings, Is.Not.Null); + Assert.That(settings.Country, Is.EqualTo(expectedCountry)); } [Test] diff --git a/src/Tests/Xtz.StronglyTyped.IntegrationTests/Settings/Country.cs b/src/Tests/Xtz.StronglyTyped.IntegrationTests/Settings/Country.cs index d20b1e6..0086421 100644 --- a/src/Tests/Xtz.StronglyTyped.IntegrationTests/Settings/Country.cs +++ b/src/Tests/Xtz.StronglyTyped.IntegrationTests/Settings/Country.cs @@ -1,5 +1,4 @@ -using System.Diagnostics.CodeAnalysis; -using Xtz.StronglyTyped.SourceGenerator; +using Xtz.StronglyTyped.SourceGenerator; namespace Xtz.StronglyTyped.IntegrationTests.Settings { diff --git a/src/Tests/Xtz.StronglyTyped.IntegrationTests/SystemTextJsonTests.cs b/src/Tests/Xtz.StronglyTyped.IntegrationTests/SystemTextJsonTests.cs index c145a5f..4d51914 100644 --- a/src/Tests/Xtz.StronglyTyped.IntegrationTests/SystemTextJsonTests.cs +++ b/src/Tests/Xtz.StronglyTyped.IntegrationTests/SystemTextJsonTests.cs @@ -48,7 +48,7 @@ public void ShouldSerialize_GivenNestedSettings() // Assert Assert.That(() => result.Contains(country)); - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [Test] @@ -67,7 +67,7 @@ public void ShouldDeserializeSettings_GivenString() // Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result.Country); + Assert.That(result.Country, Is.EqualTo(expected)); } [Test] @@ -86,7 +86,7 @@ public void ShouldDeserializeNestedSettings_GivenString() // Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result.Inner.Country); + Assert.That(result.Inner.Country, Is.EqualTo(expected)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.IntegrationTests/Xtz.StronglyTyped.IntegrationTests.csproj b/src/Tests/Xtz.StronglyTyped.IntegrationTests/Xtz.StronglyTyped.IntegrationTests.csproj index afa53be..62b5c22 100644 --- a/src/Tests/Xtz.StronglyTyped.IntegrationTests/Xtz.StronglyTyped.IntegrationTests.csproj +++ b/src/Tests/Xtz.StronglyTyped.IntegrationTests/Xtz.StronglyTyped.IntegrationTests.csproj @@ -25,14 +25,27 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + + + - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/DeserializationTests.cs b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/DeserializationTests.cs new file mode 100644 index 0000000..4b3477e --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/DeserializationTests.cs @@ -0,0 +1,778 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using Newtonsoft.Json; +using NUnit.Framework; +using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; +using Xtz.StronglyTyped.BuiltinTypes.Internet; +using Xtz.StronglyTyped.UnitTests; + +namespace Xtz.StronglyTyped.NewtonsoftJson.UnitTests +{ + public class DeserializationTests + { + private static readonly JsonSerializerSettings JSON_SERIALIZER_SETTINGS; + + static DeserializationTests() + { + var jsonSerializerSettings = new JsonSerializerSettings(); + jsonSerializerSettings.Converters.Add(new StronglyTypedNewtonsoftConverter()); + JSON_SERIALIZER_SETTINGS = jsonSerializerSettings; + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldDeserialize_ToStronglyTypedStringClass(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldDeserialize_ToStronglyTypedStringStruct(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldDeserialize_ToStronglyTypedStringClassAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldDeserialize_ToStronglyTypedStringStructAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldDeserialize_ToStronglyTypedGuidClass(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("57c2a2d3-99cc-4468-998e-f3a3abe089ca")] + public void ShouldDeserialize_ToStronglyTypedGuidStruct(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldDeserialize_ToStronglyTypedGuidIdClass(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntClass(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntStruct(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(1)] + [TestCase(546)] + [TestCase(6474)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntIdClass(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedBoolClass() + { + // Arrange + + var values = new[] { false, true }; + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + const string json = "[{\"testValue\": false }, {\"testValue\": true }]"; + + // Act + + var result = JsonConvert.DeserializeObject>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase(byte.MinValue)] + [TestCase(0)] + [TestCase(1)] + [TestCase(233)] + [TestCase(byte.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedByteClass(byte value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(char.MinValue)] + [TestCase('I')] + [TestCase('x')] + [TestCase('\xF0')] + [TestCase('Ž')] + [TestCase('£')] + [TestCase('¶')] + [TestCase('Ð')] + [TestCase('4')] + [TestCase('ߡ')] + [TestCase('ݓ')] + [TestCase('Ѝ')] + [TestCase(char.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedCharClass(char value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + public void ShouldDeserialize_ToStronglyTypedDecimalClass(decimal value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedDecimalClass() + { + // Arrange + + var values = new[] { decimal.MinValue, -968.2566m, decimal.MinusOne, decimal.Zero, decimal.One, decimal.MaxValue }; + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildNonStringArray(stronglyTyped.Select(x => x.TestValue.Value).Cast()); + + // Act + + var result = JsonConvert.DeserializeObject>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase(double.MinValue)] + [TestCase(double.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + [TestCase(double.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedDoubleClass(double value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(float.MinValue)] + [TestCase(float.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566F)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353F)] + [TestCase(float.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedFloatClass(float value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(long.MinValue)] + [TestCase(-5745)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(41343252352352)] + [TestCase(long.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedLongClass(long value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(sbyte.MinValue)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(sbyte.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedSbyteClass(sbyte value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(short.MinValue)] + [TestCase(-24633)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(7374)] + [TestCase(short.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedShortClass(short value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(uint.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(uint.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedUintClass(uint value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(ulong.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(847847645745745U)] + [TestCase(ulong.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedUlongClass(ulong value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedUshortClass() + { + var values = new[] { ushort.MinValue, (ushort)0, (ushort)1, (ushort)34, (ushort)7374, ushort.MaxValue }; + // Arrange + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildNonStringArray(stronglyTyped.Select(x => x.TestValue.Value).Cast()); + + // Act + + var result = JsonConvert.DeserializeObject>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase("2020-08-14T14:35:57+0000")] + [TestCase("2020-08-14T14:35:57-1000")] + [TestCase("2020-08-14T14:35:57Z")] + [TestCase("2320-07-21T23:00:35Z")] + [TestCase("1539-05-06T09:20:45Z")] + public void ShouldDeserialize_ToStronglyTypedDateTimeClass(DateTime value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(TimeSpan.TicksPerMillisecond)] + [TestCase(TimeSpan.TicksPerSecond)] + [TestCase(TimeSpan.TicksPerMinute)] + [TestCase(TimeSpan.TicksPerHour)] + [TestCase(TimeSpan.TicksPerDay)] + public void ShouldDeserialize_ToStronglyTypedTimeSpanClass_FromTicks(long value) + { + var timeSpan = TimeSpan.FromTicks(value); + var expected = XmlConvert.ToString(timeSpan); + + // Arrange + + var stronglyTyped = new SerializationDto(timeSpan); + var json = BuildString(expected); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("6")] + [TestCase("6:12")] + [TestCase("6:12:14")] + [TestCase("6:12:14:45")] + [TestCase("6.12:14:45")] + [TestCase("6:12:14:45.3448")] + public void ShouldDeserialize_ToStronglyTypedTimeSpanClass(TimeSpan timeSpan) + { + var expected = XmlConvert.ToString(timeSpan); + + // Arrange + + var stronglyTyped = new SerializationDto(timeSpan); + var json = BuildString(expected); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedEmailClass(Email value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(stronglyTyped.TestValue.Value.Address); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedEmailsClass(IReadOnlyCollection values) + { + // Arrange + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildStringArray(stronglyTyped.Select(x => x.TestValue.Value.Address)); + + // Act + + var result = JsonConvert.DeserializeObject>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedIpV4AddressClass(IpV4Address value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedIpV6AddressClass(IpV6Address value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedMacAddressClass(MacAddress value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonConvert.DeserializeObject>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + private static string BuildStringArray(IEnumerable values) + { + var stringBuilder = new StringBuilder("[ \n"); + + foreach (var value in values) + { + stringBuilder.AppendFormat(" {0},\n", BuildString(value)); + } + + stringBuilder.Append(']'); + var result = stringBuilder.ToString(); + return result; + } + + private static string BuildNonStringArray(IEnumerable values) + { + var stringBuilder = new StringBuilder("[ \n"); + + foreach (var value in values) + { + stringBuilder.AppendFormat(" {0},\n", BuildNonString(value)); + } + + stringBuilder.Append(']'); + var result = stringBuilder.ToString(); + return result; + } + + private static string BuildString(object value) + { + return $"{{ \"testValue\": \"{value?.ToString()?.Replace("\"", "\\\"")}\" }}"; + } + + private static string BuildNonString(object value) + { + return $"{{ \"testValue\": {value} }}"; + } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/GlobalSuppressions.cs b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/GlobalSuppressions.cs new file mode 100644 index 0000000..23b42d3 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/GlobalSuppressions.cs @@ -0,0 +1,9 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Vlad DX: Reviewed. Not possible", Scope = "member", Target = "~M:Xtz.StronglyTyped.NewtonsoftJson.UnitTests.DeserializationTests.#cctor")] +[assembly: SuppressMessage("Minor Code Smell", "S3963:\"static\" fields should be initialized inline", Justification = "Vlad DX: Reviewed. Not possible", Scope = "member", Target = "~M:Xtz.StronglyTyped.NewtonsoftJson.UnitTests.SerializationTests.#cctor")] diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/SerializationTests.cs b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/SerializationTests.cs new file mode 100644 index 0000000..3d71c91 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/SerializationTests.cs @@ -0,0 +1,692 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using Newtonsoft.Json; +using NUnit.Framework; +using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; +using Xtz.StronglyTyped.BuiltinTypes.Internet; +using Xtz.StronglyTyped.UnitTests; + +namespace Xtz.StronglyTyped.NewtonsoftJson.UnitTests +{ + public class SerializationTests + { + private static readonly JsonSerializerSettings JSON_SERIALIZER_SETTINGS; + + static SerializationTests() + { + var jsonSerializerSettings = new JsonSerializerSettings(); + jsonSerializerSettings.Converters.Add(new StronglyTypedNewtonsoftConverter()); + JSON_SERIALIZER_SETTINGS = jsonSerializerSettings; + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldSerialize_GivenStronglyTypedStringClass(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedString(value); + var json = JsonConvert.SerializeObject(value, JSON_SERIALIZER_SETTINGS); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldSerialize_GivenStronglyTypedStringStruct(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringStruct(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldSerialize_GivenStronglyTypedStringClassAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringAllowEmpty(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldSerialize_GivenStronglyTypedStringStructAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringAllowEmptyStruct(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldSerialize_GivenStronglyTypedGuidClass(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuid(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("57c2a2d3-99cc-4468-998e-f3a3abe089ca")] + public void ShouldSerialize_GivenStronglyTypedGuidStruct(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuidStruct(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldSerialize_GivenStronglyTypedGuidIdClass(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuidId(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntClass(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedInt(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntStruct(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedIntStruct(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(1)] + [TestCase(546)] + [TestCase(6474)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntIdClass(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedIntId(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void ShouldSerialize_GivenStronglyTypedBoolClass(bool value) + { + // Arrange + + var stronglyTyped = new StronglyTypedBool(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(byte.MinValue)] + [TestCase(0)] + [TestCase(1)] + [TestCase(233)] + [TestCase(byte.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedByteClass(byte value) + { + // Arrange + + var stronglyTyped = new StronglyTypedByte(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(char.MinValue)] + [TestCase('I')] + [TestCase('x')] + [TestCase('\xF0')] + [TestCase('Ž')] + [TestCase('£')] + [TestCase('¶')] + [TestCase('Ð')] + [TestCase('4')] + [TestCase('ߡ')] + [TestCase('ݓ')] + [TestCase('Ѝ')] + [TestCase(char.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedCharClass(char value) + { + // Arrange + + var stronglyTyped = new StronglyTypedChar(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + public void ShouldSerialize_GivenStronglyTypedDecimalClass(decimal value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDecimal(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + public void ShouldSerialize_GivenStronglyTypedDecimalClass() + { + // Arrange + + var values = new [] { decimal.MinValue, -968.2566m, decimal.MinusOne, decimal.Zero, decimal.One, decimal.MaxValue }; + + var stronglyTyped = values.Select(x => (StronglyTypedDecimal)x); + var json = JsonConvert.SerializeObject(values); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(double.MinValue)] + [TestCase(double.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + [TestCase(double.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedDoubleClass(double value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDouble(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(float.MinValue)] + [TestCase(float.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566F)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353F)] + [TestCase(float.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedFloatClass(float value) + { + // Arrange + + var stronglyTyped = new StronglyTypedFloat(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(long.MinValue)] + [TestCase(-5745)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(41343252352352)] + [TestCase(long.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedLongClass(long value) + { + // Arrange + + var stronglyTyped = new StronglyTypedLong(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(sbyte.MinValue)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(sbyte.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedSbyteClass(sbyte value) + { + // Arrange + + var stronglyTyped = new StronglyTypedSbyte(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(short.MinValue)] + [TestCase(-24633)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(7374)] + [TestCase(short.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedShortClass(short value) + { + // Arrange + + var stronglyTyped = new StronglyTypedShort(value); + var json = JsonConvert.SerializeObject(value, JSON_SERIALIZER_SETTINGS); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(uint.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(uint.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedUintClass(uint value) + { + // Arrange + + var stronglyTyped = new StronglyTypedUint(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(ulong.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(847847645745745U)] + [TestCase(ulong.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedUlongClass(ulong value) + { + // Arrange + + var stronglyTyped = new StronglyTypedUlong(value); + var json = JsonConvert.SerializeObject(value); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + public void ShouldSerialize_GivenStronglyTypedUshortClass() + { + // Arrange + + var values = new[] { ushort.MinValue, (ushort)0, (ushort)1, (ushort)34, (ushort)7374, ushort.MaxValue }; + + var stronglyTyped = values.Select(x => (StronglyTypedUshort)x); + var json = JsonConvert.SerializeObject(values); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("2020-08-14T14:35:57+0000")] + [TestCase("2020-08-14T14:35:57-1000")] + [TestCase("2020-08-14T14:35:57Z")] + [TestCase("2320-07-21T23:00:35Z")] + [TestCase("1539-05-06T09:20:45Z")] + public void ShouldSerialize_GivenStronglyTypedDateTimeClass(DateTime value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDateTime(value); + var json = JsonConvert.SerializeObject(value.ToUniversalTime()); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(TimeSpan.TicksPerMillisecond)] + [TestCase(TimeSpan.TicksPerSecond)] + [TestCase(TimeSpan.TicksPerMinute)] + [TestCase(TimeSpan.TicksPerHour)] + [TestCase(TimeSpan.TicksPerDay)] + public void ShouldSerialize_GivenStronglyTypedTimeSpanClass_FromTicks(long value) + { + // Arrange + + var timeSpan = TimeSpan.FromTicks(value); + var stronglyTyped = new StronglyTypedTimeSpan(timeSpan); + var expected = $"\"{XmlConvert.ToString(stronglyTyped)}\""; + var expectedString = $"\"{stronglyTyped}\""; + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result, Is.EqualTo(expectedString)); + } + + [Test] + [TestCase("6")] + [TestCase("6:12")] + [TestCase("6:12:14")] + [TestCase("6:12:14:45")] + [TestCase("6.12:14:45")] + [TestCase("6:12:14:45.3448")] + public void ShouldSerialize_GivenStronglyTypedTimeSpanClass(TimeSpan value) + { + // Arrange + + var stronglyTyped = new StronglyTypedTimeSpan(value); + var expected = $"\"{XmlConvert.ToString(value)}\""; + var expectedString = $"\"{stronglyTyped}\""; + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result, Is.EqualTo(expectedString)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedEmailClass(Email stronglyTyped) + { + // Arrange + + var json = JsonConvert.SerializeObject(stronglyTyped.Value.Address); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedEmailsClass(IReadOnlyCollection stronglyTyped) + { + // Arrange + + var collection = stronglyTyped.Select(x => x.Value.Address).ToArray(); + var json = JsonConvert.SerializeObject(collection); + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(collection, Is.Not.Empty); + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedIpV4AddressClass(IpV4Address stronglyTyped) + { + // Arrange + + var expected = $"\"{stronglyTyped.Value}\""; + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedIpV6AddressClass(IpV6Address stronglyTyped) + { + // Arrange + + var expected = $"\"{stronglyTyped.Value}\""; + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedMacAddressClass(MacAddress stronglyTyped) + { + // Arrange + + var expectedToString = $"\"{stronglyTyped.Value}\""; + var expected = $"\"{stronglyTyped.ToString(MacAddress.Separator.Hyphen)}\""; + + // Act + + var result = JsonConvert.SerializeObject(stronglyTyped, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Replace("-", string.Empty), Is.EqualTo(expectedToString)); + } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj new file mode 100644 index 0000000..9761e6a --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj @@ -0,0 +1,47 @@ + + + + net5 + preview + + + + + + + + + True + $(BaseIntermediateOutputPath)\GeneratedFiles + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj.DotSettings b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj.DotSettings new file mode 100644 index 0000000..eaf4b15 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/_TestModels/SerializationDto.cs b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/_TestModels/SerializationDto.cs new file mode 100644 index 0000000..23599cd --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.NewtonsoftJson.UnitTests/_TestModels/SerializationDto.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics; + +namespace Xtz.StronglyTyped.NewtonsoftJson.UnitTests +{ + [DebuggerDisplay("{TestValue,nq}")] + public class SerializationDto + where TStronglyTyped : IStronglyTyped + { + public SerializationDto() + { + } + + public SerializationDto(TStronglyTyped stronglyTyped) + { + TestValue = stronglyTyped; + } + + public SerializationDto(object value) + { + TestValue = (TStronglyTyped)Activator.CreateInstance(typeof(TStronglyTyped), value); + } + + public TStronglyTyped TestValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/BasicGeneratorTests.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/BasicGeneratorTests.cs index 6093552..d346430 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/BasicGeneratorTests.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/BasicGeneratorTests.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -6,6 +5,8 @@ namespace Xtz.StronglyTyped.SourceGenerator.IntegrationTests { + // TODO: Write unit tests for `DataExtractor` + public class BasicGeneratorTests : GeneratorTestsBase { [Test] @@ -101,16 +102,16 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(4, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(4)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsFalse(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.False); } [Test] @@ -147,16 +148,16 @@ public class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(5, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(5)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsFalse(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.False); } [Test] @@ -183,16 +184,16 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(5, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(5)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsFalse(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.False); } [Test] @@ -216,16 +217,16 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(4, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(4)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.True); } [Test] @@ -252,16 +253,16 @@ public partial record City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(4, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(4)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.True); } [Test] @@ -292,16 +293,16 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); //// Assert - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(4, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(4)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.True); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CompileAndRunGeneratorTests.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CompileAndRunGeneratorTests.cs index 68477c6..bfa1fb9 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CompileAndRunGeneratorTests.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CompileAndRunGeneratorTests.cs @@ -64,7 +64,7 @@ public partial class DegreesCelsius3 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); var compiledBytes = CompileBytes(outputCompilation); @@ -73,7 +73,7 @@ public partial class DegreesCelsius3 // Assert - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } [Test] @@ -115,7 +115,7 @@ public class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CustomizedGeneratorTests.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CustomizedGeneratorTests.cs index 73f484b..d01bb63 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CustomizedGeneratorTests.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/CustomizedGeneratorTests.cs @@ -5,6 +5,8 @@ namespace Xtz.StronglyTyped.SourceGenerator.IntegrationTests { + // TODO: Write tests for incomplete code (e.g. `[StrongType(]`) to test that generator ignores such cases + public class CustomizedGeneratorTests : GeneratorTestsBase { [Test] @@ -12,7 +14,7 @@ public void ShouldGenerate_NoNull_ByDefault() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -45,10 +47,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -60,8 +59,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -69,7 +68,7 @@ public void ShouldGenerate_NoEmpty_ByDefault() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -102,10 +101,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -117,8 +113,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } [Test] @@ -126,7 +122,7 @@ public void ShouldGenerate_NoNull_WhenStringTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -159,10 +155,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -174,8 +167,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -183,7 +176,7 @@ public void ShouldGenerate_NoEmpty_WhenStringTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -216,10 +209,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -231,8 +221,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } //// [Test] @@ -275,7 +265,6 @@ void Action() //// // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls //// driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - //// var compiledBytes = CompileBytes(outputCompilation); //// [ExcludeFromCodeCoverage] @@ -297,7 +286,7 @@ public void ShouldGenerate_NoNull_WhenUriTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -330,10 +319,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -345,8 +331,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -354,7 +340,7 @@ public void ShouldGenerate_NoNull_WhenMailAddressTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -388,10 +374,7 @@ public partial class CityEmail2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -403,8 +386,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -412,7 +395,7 @@ public void ShouldGenerate_NoNull_WhenIPAddressTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -446,10 +429,7 @@ public partial class CityIpAddress2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -461,8 +441,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -470,7 +450,7 @@ public void ShouldGenerate_NoNull_WhenPhysicalAddressTypeProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -504,10 +484,7 @@ public partial class CityMacAddress2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -519,8 +496,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -528,7 +505,7 @@ public void ShouldGenerate_NoNull_WhenAllowUnknownProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -542,7 +519,7 @@ public static int Main(string[] args) } } - [StrongType(Allow.Unknown)] + [StrongType(Allow.None)] public partial class City2 { } @@ -561,10 +538,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -576,8 +550,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -585,7 +559,7 @@ public void ShouldGenerate_NoEmpty_WhenAllowUnknownProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -599,7 +573,7 @@ public static int Main(string[] args) } } - [StrongType(Allow.Unknown)] + [StrongType(Allow.None)] public partial class City2 { } @@ -618,10 +592,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -633,8 +604,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } [Test] @@ -642,7 +613,7 @@ public void ShouldGenerate_NoNull_WhenStringTypeAllowUnknownProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -656,7 +627,7 @@ public static int Main(string[] args) } } - [StrongType(typeof(string), Allow.Unknown)] + [StrongType(typeof(string), Allow.None)] public partial class CityUri2 { } @@ -675,10 +646,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -690,8 +658,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -699,7 +667,7 @@ public void ShouldGenerate_NoEmpty_WhenStringTypeAllowUnknownProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -713,7 +681,7 @@ public static int Main(string[] args) } } - [StrongType(typeof(string), Allow.Unknown)] + [StrongType(typeof(string), Allow.None)] public partial class CityUri2 { } @@ -732,10 +700,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -747,8 +712,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } [Test] @@ -756,7 +721,7 @@ public void ShouldGenerate_NoNull_WhenInvalidAllowProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -789,10 +754,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -804,8 +766,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -813,7 +775,7 @@ public void ShouldGenerate_NoEmpty_WhenInvalidAllowProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -846,10 +808,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -861,8 +820,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } [Test] @@ -870,7 +829,7 @@ public void ShouldGenerate_NoNull_WhenStringTypeInvalidAllowProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -903,10 +862,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -918,8 +874,8 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains(""), Is.True); } [Test] @@ -927,7 +883,7 @@ public void ShouldGenerate_NoEmpty_WhenStringTypeInvalidAllowProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -960,10 +916,7 @@ public partial class CityUri2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - - - var compiledBytes = CompileBytes(outputCompilation); + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); [ExcludeFromCodeCoverage] void Action() @@ -975,10 +928,11 @@ void Action() //// Assert var exception = Assert.Throws(Action); - Assert.IsInstanceOf(exception?.InnerException); - Assert.IsTrue(exception?.InnerException?.Message.Contains("''")); + Assert.That(exception?.InnerException, Is.InstanceOf()); + Assert.That(exception?.InnerException?.Message.Contains("''"), Is.True); } +#pragma warning disable S125 // [Test] // public void ShouldGenerate_AllowNull_WhenAllowNullProvided() // { @@ -1019,7 +973,6 @@ void Action() // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1069,7 +1022,6 @@ void Action() // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1119,7 +1071,6 @@ void Action() // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1169,7 +1120,6 @@ void Action() // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1178,13 +1128,14 @@ void Action() // Assert.AreEqual(0, result); // } +#pragma warning restore S125 [Test] public void ShouldGenerate_AllowEmpty_WhenAllowEmptyProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -1217,8 +1168,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); var compiledBytes = CompileBytes(outputCompilation); @@ -1226,7 +1176,7 @@ public partial class City2 // Assert - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } [Test] @@ -1234,7 +1184,7 @@ public void ShouldGenerate_AllowEmpty_WhenDoubleAllowEmptyProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -1267,8 +1217,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); var compiledBytes = CompileBytes(outputCompilation); @@ -1276,7 +1225,7 @@ public partial class City2 // Assert - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } [Test] @@ -1284,7 +1233,7 @@ public void ShouldGenerate_AllowEmpty_WhenTripleAllowEmptyProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -1317,8 +1266,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); var compiledBytes = CompileBytes(outputCompilation); @@ -1326,7 +1274,7 @@ public partial class City2 // Assert - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } [Test] @@ -1334,7 +1282,7 @@ public void ShouldGenerate_AllowEmpty_WhenNamedEmptyProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -1367,8 +1315,7 @@ public partial class City2 GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls - driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - + driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); var compiledBytes = CompileBytes(outputCompilation); @@ -1376,9 +1323,10 @@ public partial class City2 // Assert - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } +#pragma warning disable S125 // [Test] // public void ShouldGenerate_AllowEmpty_WhenTypeAndAllowNullEmptyProvided() // { @@ -1419,7 +1367,6 @@ public partial class City2 // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1469,7 +1416,6 @@ public partial class City2 // // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls // driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out _); - // var compiledBytes = CompileBytes(outputCompilation); // var result = LoadAndExecute(compiledBytes); @@ -1478,5 +1424,6 @@ public partial class City2 // Assert.AreEqual(0, result); // } +#pragma warning restore S125 } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/GlobalSuppressions.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/GlobalSuppressions.cs new file mode 100644 index 0000000..bbb53d1 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/GlobalSuppressions.cs @@ -0,0 +1,13 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.GeneratorTestsException")] +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.TestsExecutionException")] +[assembly: SuppressMessage("Major Code Smell", "S1118:Utility classes should not have public constructors", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.GeneratorTestsBase")] +[assembly: SuppressMessage("Performance", "RCS1197:Optimize StringBuilder.Append/AppendLine call.", Justification = "Vlad DX: Reviewed. More readable", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.GeneratorTestsBase.CompileBytes(Microsoft.CodeAnalysis.Compilation)~System.Byte[]")] +[assembly: SuppressMessage("Major Code Smell", "S4144:Methods should not have identical implementations", Justification = "Vlad DX: Reviewed. It's intentional", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.InnerTypesGeneratorTests.ShouldGenerateClass_ForKnownTypes(System.Type)")] +[assembly: SuppressMessage("Major Code Smell", "S4144:Methods should not have identical implementations", Justification = "Vlad DX: Reviewed. It's intentional", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.IntegrationTests.InnerTypesGeneratorTests.ShouldGenerateStruct_ForKnownTypes(System.Type)")] diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/InnerTypesGeneratorTests.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/InnerTypesGeneratorTests.cs index 5f73b6b..46dcb0d 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/InnerTypesGeneratorTests.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/InnerTypesGeneratorTests.cs @@ -25,7 +25,7 @@ public class InnerTypesGeneratorTests : GeneratorTestsBase [TestCase(typeof(uint))] [TestCase(typeof(ulong))] [TestCase(typeof(ushort))] - public void ShouldGenerate_ForPrimitiveTypes(Type innerType) + public void ShouldGenerateClass_ForPrimitiveTypes(Type innerType) { //// Arrange @@ -63,7 +63,7 @@ public partial class WithInnerType [TestCase(typeof(MailAddress))] [TestCase(typeof(IPAddress))] [TestCase(typeof(PhysicalAddress))] - public void ShouldGenerate_ForKnownTypes(Type innerType) + public void ShouldGenerateClass_ForKnownTypes(Type innerType) { //// Arrange @@ -92,5 +92,88 @@ public partial class WithInnerType AssertGenerationSuccess(4, diagnostics, outputCompilation, driver.GetRunResult()); } + + [Test] + [TestCase(typeof(bool))] + [TestCase(typeof(byte))] + [TestCase(typeof(char))] + [TestCase(typeof(decimal))] + [TestCase(typeof(double))] + [TestCase(typeof(float))] + [TestCase(typeof(int))] + [TestCase(typeof(long))] + [TestCase(typeof(sbyte))] + [TestCase(typeof(short))] + [TestCase(typeof(string))] + [TestCase(typeof(uint))] + [TestCase(typeof(ulong))] + [TestCase(typeof(ushort))] + public void ShouldGenerateStruct_ForPrimitiveTypes(Type innerType) + { + //// Arrange + + var sourceCode = $@" +namespace IntegrationTests.Generated +{{ + using Xtz.StronglyTyped.SourceGenerator; + + [StrongType(typeof({innerType.FullName}))] + public partial struct WithInnerType + {{ + }} +}} + "; + + var inputCompilation = CreateCompilation(sourceCode, OutputKind.DynamicallyLinkedLibrary); + + //// Act + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); + + // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls + driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + + //// Assert + + AssertGenerationSuccess(4, diagnostics, outputCompilation, driver.GetRunResult()); + } + + [Test] + [TestCase(typeof(DateTime))] + [TestCase(typeof(TimeSpan))] + [TestCase(typeof(Guid))] + [TestCase(typeof(Uri))] + [TestCase(typeof(MailAddress))] + [TestCase(typeof(IPAddress))] + [TestCase(typeof(PhysicalAddress))] + public void ShouldGenerateStruct_ForKnownTypes(Type innerType) + { + //// Arrange + + var sourceCode = $@" +namespace IntegrationTests.Generated +{{ + using Xtz.StronglyTyped.SourceGenerator; + + [StrongType(typeof({innerType.FullName}))] + public partial struct WithInnerType + {{ + }} +}} + "; + + var inputCompilation = CreateCompilation(sourceCode, OutputKind.DynamicallyLinkedLibrary); + + //// Act + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new StronglyTypedGenerator()); + + // NOTE: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls + driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); + + //// Assert + + AssertGenerationSuccess(4, diagnostics, outputCompilation, driver.GetRunResult()); + } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/GeneratorTestsBase.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/GeneratorTestsBase.cs index ec36797..8714e28 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/GeneratorTestsBase.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/GeneratorTestsBase.cs @@ -110,23 +110,23 @@ protected static object LoadAndExecute(byte[] compiledAssembly, params string[] protected static void AssertGenerationSuccess(int treeNumber, ImmutableArray diagnostics, Compilation outputCompilation, GeneratorDriverRunResult runResult) { - Assert.IsTrue(diagnostics.IsEmpty); + Assert.That(diagnostics.IsEmpty, Is.True); // Input syntax tree, a generated one, and logs - Assert.AreEqual(treeNumber + 1, outputCompilation.SyntaxTrees.Count()); + Assert.That(outputCompilation.SyntaxTrees.Count(), Is.EqualTo(treeNumber + 1)); PrintDiagnosticsToDebug(outputCompilation); - Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); + Assert.That(outputCompilation.GetDiagnostics().IsEmpty, Is.True); // A generated syntax tree and logs - Assert.AreEqual(treeNumber, runResult.GeneratedTrees.Length); - Assert.IsTrue(runResult.Diagnostics.IsEmpty); + Assert.That(runResult.GeneratedTrees.Length, Is.EqualTo(treeNumber)); + Assert.That(runResult.Diagnostics.IsEmpty, Is.True); // Asserting the individual results on a by-generator basis var generatorResult = runResult.Results[0]; - Assert.AreEqual(typeof(StronglyTypedGenerator), generatorResult.Generator.GetType()); - Assert.IsTrue(generatorResult.Diagnostics.IsEmpty); - Assert.AreEqual(treeNumber, generatorResult.GeneratedSources.Length); - Assert.IsNull(generatorResult.Exception); + Assert.That(generatorResult.Generator.GetType(), Is.EqualTo(typeof(StronglyTypedGenerator))); + Assert.That(generatorResult.Diagnostics.IsEmpty, Is.True); + Assert.That(generatorResult.GeneratedSources.Length, Is.EqualTo(treeNumber)); + Assert.That(generatorResult.Exception, Is.Null); } [ExcludeFromCodeCoverage] diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/SimpleUnloadableAssemblyLoadContext.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/SimpleUnloadableAssemblyLoadContext.cs index 5eba32e..d6d55bb 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/SimpleUnloadableAssemblyLoadContext.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Misc/SimpleUnloadableAssemblyLoadContext.cs @@ -4,7 +4,7 @@ namespace Xtz.StronglyTyped.SourceGenerator.IntegrationTests { - internal class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext, IDisposable + internal sealed class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext, IDisposable { public SimpleUnloadableAssemblyLoadContext() : base(true) diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/StructGeneratorTests.cs b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/StructGeneratorTests.cs index f12c14d..b580ea0 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/StructGeneratorTests.cs +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/StructGeneratorTests.cs @@ -11,7 +11,7 @@ public void ShouldGeneratePartialStruct_WhenAttributeProvidedAndIsValidExists() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped; @@ -56,7 +56,7 @@ public void ShouldGeneratePartialStruct_WhenAttributeProvidedAndToStringExists() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; @@ -88,7 +88,7 @@ public void ShouldGenerateThrowIfInvalid_WhenIsValidMethodProvided() { //// Arrange - var sourceCode = @" + const string sourceCode = @" namespace IntegrationTests.Generated { using Xtz.StronglyTyped.SourceGenerator; diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj index 5592dca..81137d4 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj @@ -16,12 +16,25 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + + + - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj.DotSettings b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj.DotSettings index e492290..9fec72c 100644 --- a/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj.DotSettings +++ b/src/Tests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests/Xtz.StronglyTyped.SourceGenerator.IntegrationTests.csproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/ConversionTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/ConversionTests.cs index a77264a..86d5b69 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/ConversionTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/ConversionTests.cs @@ -21,7 +21,7 @@ public void ShouldParseStronglyTyped_GivenString_WhenExplicitlyConverted(string //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("Norway")] @@ -38,7 +38,7 @@ public void ShouldConvertToString_GivenStronglyTyped_WhenExplicitlyConverted(str //// Assert - Assert.AreEqual(country, result); + Assert.That(result, Is.EqualTo(country)); } [TestCase("Norway")] @@ -55,7 +55,7 @@ public void ShouldConvertToString_GivenStronglyTyped_WhenImplicitlyConverted(str //// Assert - Assert.AreEqual(country, result); + Assert.That(result, Is.EqualTo(country)); } [TestCase("Norway")] @@ -72,7 +72,7 @@ public void Convert_ShouldConvertToString_GivenCountry(string country) //// Assert - Assert.AreEqual(country, result); + Assert.That(result, Is.EqualTo(country)); } [TestCase(27)] @@ -89,24 +89,7 @@ public void Convert_ShouldConvertToInt_GivenCountryId(int countryId) //// Assert - Assert.AreEqual(countryId, result); - } - - [TestCase(27)] - [Test] - public void Convert_ShouldConvertToInt_GivenCountryIdAsObject(int countryId) - { - //// Arrange - - object stronglyTyped = new CountryId(countryId); - - //// Act - - var result = Convert.ToInt32(stronglyTyped, CultureInfo.InvariantCulture); - - //// Assert - - Assert.AreEqual(countryId, result); + Assert.That(result, Is.EqualTo(countryId)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/CountryIdTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/CountryIdTests.cs index c973c77..c9bd1b3 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/CountryIdTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/CountryIdTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using System; +using System.Diagnostics.CodeAnalysis; namespace Xtz.StronglyTyped.UnitTests.Basic { @@ -19,7 +20,7 @@ public void CountryId_ShouldSucceed_GivenValidValue(int value) //// Assert - Assert.AreEqual(value, result.Value); + Assert.That(result.Value, Is.EqualTo(value)); } [TestCase(Int32.MinValue)] @@ -32,6 +33,7 @@ public void CountryId_ShouldThrow_GivenInvalidValue(int value) //// Act + [ExcludeFromCodeCoverage] // ReSharper disable once ObjectCreationAsStatement void Action() => new CountryId(value); @@ -50,6 +52,8 @@ public void CountryIdImplicitOperator_ShouldThrow_GivenDifferentType(object valu //// Act + [ExcludeFromCodeCoverage] + // ReSharper disable once UnusedLocalFunctionReturnValue CountryId Action() => (CountryId)value; //// Assert diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringCreationTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringCreationTests.cs index 80ef7da..9124236 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringCreationTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringCreationTests.cs @@ -17,8 +17,8 @@ public void ShouldInstantiate_GivenString(string country) //// Assert - Assert.NotNull(result); - Assert.AreEqual(country, result.Value); + Assert.That(result, Is.Not.Null); + Assert.That(result.Value, Is.EqualTo(country)); } [TestCase("Norway")] @@ -35,7 +35,7 @@ public void ShouldReturnInnerValue_WhenToString(string country) //// Assert - Assert.AreEqual(country, result); + Assert.That(result, Is.EqualTo(country)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityOperatorsTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityOperatorsTests.cs index 6ba281c..cef41cf 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityOperatorsTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityOperatorsTests.cs @@ -17,7 +17,8 @@ public void EqualsOperator_ShouldBeTrue_ForSameStronglyTypedValues() //// Assert #pragma warning disable CS1718 // Comparison made to same variable - Assert.IsTrue(value == value); + // ReSharper disable once EqualExpressionComparison + Assert.That(value == value, Is.True); #pragma warning restore CS1718 // Comparison made to same variable } @@ -33,8 +34,8 @@ public void EqualsOperator_ShouldBeTrue_ForSameValuesStronglyTypedAndObject() //// Assert - Assert.IsTrue(value == objValue); - Assert.IsTrue(objValue == value); + Assert.That(value == objValue, Is.True); + Assert.That(objValue == value, Is.True); } [Test] @@ -49,8 +50,8 @@ public void EqualsOperator_ShouldBeTrue_ForStronglyTypedValues_GivenSameStrings( //// Assert - Assert.IsTrue(value1 == value2); - Assert.IsTrue(value2 == value1); + Assert.That(value1 == value2, Is.True); + Assert.That(value2 == value1, Is.True); } [Test] @@ -65,8 +66,8 @@ public void EqualsOperator_ShouldBeTrue_ForStronglyTypedAndObject_GivenSameStrin //// Assert - Assert.IsTrue(value == objValue); - Assert.IsTrue(objValue == value); + Assert.That(value == objValue, Is.True); + Assert.That(objValue == value, Is.True); } [Test] @@ -81,8 +82,8 @@ public void EqualsOperator_ShouldBeFalse_ForStronglyTypedValues_GivenDifferentSt //// Assert - Assert.IsFalse(value1 == value2); - Assert.IsFalse(value2 == value1); + Assert.That(value1 == value2, Is.False); + Assert.That(value2 == value1, Is.False); } [Test] @@ -97,8 +98,8 @@ public void EqualsOperator_ShouldBeFalse_ForStronglyTypedAndObject_GivenDifferen //// Assert - Assert.IsFalse(value == objValue); - Assert.IsFalse(objValue == value); + Assert.That(value == objValue, Is.False); + Assert.That(objValue == value, Is.False); } [Test] @@ -113,8 +114,8 @@ public void NotEqualsOperator_ShouldBeFalse_ForStronglyTypedValues_GivenSameStri //// Assert - Assert.IsFalse(value1 != value2); - Assert.IsFalse(value2 != value1); + Assert.That(value1 != value2, Is.False); + Assert.That(value2 != value1, Is.False); } [Test] @@ -129,8 +130,8 @@ public void NotEqualsOperator_ShouldBeFalse_ForStronglyTypedAndObject_GivenSameS //// Assert - Assert.IsFalse(value != objValue); - Assert.IsFalse(objValue != value); + Assert.That(value != objValue, Is.False); + Assert.That(objValue != value, Is.False); } [Test] @@ -145,8 +146,8 @@ public void NotEqualsOperator_ShouldBeTrue_ForStronglyTypedValues_GivenDifferent //// Assert - Assert.IsTrue(value1 != value2); - Assert.IsTrue(value2 != value1); + Assert.That(value1 != value2, Is.True); + Assert.That(value2 != value1, Is.True); } [Test] @@ -161,8 +162,8 @@ public void NotEqualsOperator_ShouldBeTrue_ForStronglyTypedAndObject_GivenDiffer //// Assert - Assert.IsTrue(value != objValue); - Assert.IsTrue(objValue != value); + Assert.That(value != objValue, Is.True); + Assert.That(objValue != value, Is.True); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityTests.cs index 4a4f0b8..f3c4257 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/StringEqualityTests.cs @@ -18,8 +18,8 @@ public void StronglyTypedValues_ShouldBeEqual_GivenSameStrings(string country) //// Assert - Assert.AreEqual(result1, result2); - Assert.AreEqual(result1.Value, result2.Value); + Assert.That(result2, Is.EqualTo(result1)); + Assert.That(result2.Value, Is.EqualTo(result1.Value)); } [TestCase("Norway", "Denmark")] @@ -35,8 +35,8 @@ public void StronglyTypedValues_ShouldBeNotEqual_GivenDifferentStrings(string co //// Assert - Assert.AreNotEqual(result1, result2); - Assert.AreNotEqual(result1.Value, result2.Value); + Assert.That(result2, Is.Not.EqualTo(result1)); + Assert.That(result2.Value, Is.Not.EqualTo(result1.Value)); } [TestCase("Norway")] @@ -52,8 +52,8 @@ public void ShouldBeEqual_GivenTheSameCalculatedStrings(string country) //// Assert - Assert.AreEqual(result1, result2); - Assert.AreEqual(result1.Value, result2.Value); + Assert.That(result2, Is.EqualTo(result1)); + Assert.That(result2.Value, Is.EqualTo(result1.Value)); } [TestCase("Norway")] @@ -69,8 +69,8 @@ public void ShouldBeNotEqual_GivenTheDifferentlyCasedValues(string country) //// Assert - Assert.AreNotEqual(result1, result2); - Assert.AreEqual(result1.Value, result2.Value.ToUpper()); + Assert.That(result2, Is.Not.EqualTo(result1)); + Assert.That(result2.Value.ToUpper(), Is.EqualTo(result1.Value)); } [TestCase("Norway")] @@ -86,8 +86,8 @@ public void GetHashCode_ShouldBeEqual_GivenSameStrings(string country) //// Assert - Assert.AreEqual(result1.GetHashCode(), result2.GetHashCode()); - Assert.AreEqual(result1.GetHashCode(), result2.GetHashCode()); + Assert.That(result2.GetHashCode(), Is.EqualTo(result1.GetHashCode())); + Assert.That(result2.GetHashCode(), Is.EqualTo(result1.GetHashCode())); } [TestCase("Norway", "Denmark")] @@ -103,7 +103,7 @@ public void GetHashCode_ShouldBeNotEqual_GivenDifferentStrings(string country1, //// Assert - Assert.AreNotEqual(result1.GetHashCode(), result2.GetHashCode()); + Assert.That(result2.GetHashCode(), Is.Not.EqualTo(result1.GetHashCode())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UpperCasedTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UpperCasedTests.cs index f56dbed..47418ff 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UpperCasedTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UpperCasedTests.cs @@ -21,7 +21,7 @@ public void StronglyTyped_ShouldBeUpperCased_GivenCasedString(string value) //// Assert - Assert.AreEqual(expected, result.Value); + Assert.That(result.Value, Is.EqualTo(expected)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UserIdTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UserIdTests.cs index 1d863e2..53f5639 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UserIdTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Basic/UserIdTests.cs @@ -19,7 +19,7 @@ public void UserId_ShouldInstantiate_GivenGuid() //// Assert - Assert.AreNotEqual(Guid.Empty, result); + Assert.That(result, Is.Not.EqualTo(Guid.Empty)); } [Test] @@ -32,6 +32,7 @@ public void UserId_ShouldThrow_GivenInvalidValue() //// Act [ExcludeFromCodeCoverage] + // ReSharper disable once ObjectCreationAsStatement void Action() => new UserId(value); //// Assert diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/GlobalSuppressions.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/GlobalSuppressions.cs new file mode 100644 index 0000000..3a7ab8a --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/GlobalSuppressions.cs @@ -0,0 +1,17 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.CountryIdTests.CountryId_ShouldThrow_GivenInvalidValue(System.Int32)")] +[assembly: SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Values.CreationTests.ShouldThrow_GivenNullOrEmpty(System.String)")] +[assembly: SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.UserIdTests.UserId_ShouldThrow_GivenInvalidValue")] +[assembly: SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Values.CreationTests.ShouldThrow_GivenNull_ForAllowEmpty")] +[assembly: SuppressMessage("Assertion", "NUnit2021:Incompatible types for EqualTo constraint", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.UserIdTests.UserId_ShouldInstantiate_GivenGuid")] +[assembly: SuppressMessage("Minor Code Smell", "S3241:Methods should not return values that are never used", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.CountryIdTests.CountryIdImplicitOperator_ShouldThrow_GivenDifferentType(System.Object)")] +[assembly: SuppressMessage("Assertion", "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.StringEqualityOperatorsTests.EqualsOperator_ShouldBeTrue_ForSameStronglyTypedValues")] +[assembly: SuppressMessage("Major Bug", "S1764:Identical expressions should not be used on both sides of a binary operator", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "member", Target = "~M:Xtz.StronglyTyped.UnitTests.Basic.StringEqualityOperatorsTests.EqualsOperator_ShouldBeTrue_ForSameStronglyTypedValues")] +[assembly: SuppressMessage("Assertion", "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "type", Target = "~T:Xtz.StronglyTyped.UnitTests.Values.EqualityOperatorsTests")] +[assembly: SuppressMessage("Assertion", "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", Justification = "Vlad DX: Reviewed (unit tests)", Scope = "type", Target = "~T:Xtz.StronglyTyped.UnitTests.Basic.StringEqualityOperatorsTests")] diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/DeserializationTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/DeserializationTests.cs new file mode 100644 index 0000000..ce3d4fb --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/DeserializationTests.cs @@ -0,0 +1,793 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Xml; +using NUnit.Framework; +using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; +using Xtz.StronglyTyped.BuiltinTypes.Internet; + +namespace Xtz.StronglyTyped.UnitTests.SystemTextJson +{ + public class DeserializationTests + { + private static readonly JsonSerializerOptions JSON_SERIALIZER_SETTINGS = new() + { + PropertyNameCaseInsensitive = true, + AllowTrailingCommas = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldDeserialize_ToStronglyTypedStringClass(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldDeserialize_ToStronglyTypedStringStruct(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldDeserialize_ToStronglyTypedStringClassAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldDeserialize_ToStronglyTypedStringStructAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldDeserialize_ToStronglyTypedGuidClass(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("57c2a2d3-99cc-4468-998e-f3a3abe089ca")] + public void ShouldDeserialize_ToStronglyTypedGuidStruct(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldDeserialize_ToStronglyTypedGuidIdClass(Guid value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntClass(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntStruct(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(1)] + [TestCase(546)] + [TestCase(6474)] + [TestCase(int.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedIntIdClass(int value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedBoolClass() + { + // Arrange + + var values = new[] { false, true }; + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + const string json = "[{\"testValue\": false }, {\"testValue\": true }]"; + + // Act + + var result = JsonSerializer.Deserialize>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase(byte.MinValue)] + [TestCase(0)] + [TestCase(1)] + [TestCase(233)] + [TestCase(byte.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedByteClass(byte value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase('I')] + [TestCase('x')] + [TestCase('\xF0')] + [TestCase('Ž')] + [TestCase('£')] + [TestCase('¶')] + [TestCase('Ð')] + [TestCase('4')] + [TestCase('ߡ')] + [TestCase('ݓ')] + [TestCase('Ѝ')] + [TestCase(char.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedCharClass(char value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(char.MinValue, "\\u0000")] + public void ShouldDeserialize_ToStronglyTypedCharClass(char value, string serializedValue) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(serializedValue); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + public void ShouldDeserialize_ToStronglyTypedDecimalClass(decimal value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedDecimalClass() + { + // Arrange + + var values = new[] { decimal.MinValue, -968.2566m, decimal.MinusOne, decimal.Zero, decimal.One, decimal.MaxValue }; + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildNonStringArray(stronglyTyped.Select(x => x.TestValue.Value).Cast()); + + // Act + + var result = JsonSerializer.Deserialize>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase(double.MinValue)] + [TestCase(double.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + [TestCase(double.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedDoubleClass(double value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(float.MinValue)] + [TestCase(float.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566F)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353F)] + [TestCase(float.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedFloatClass(float value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(long.MinValue)] + [TestCase(-5745)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(41343252352352)] + [TestCase(long.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedLongClass(long value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(sbyte.MinValue)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(sbyte.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedSbyteClass(sbyte value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(short.MinValue)] + [TestCase(-24633)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(7374)] + [TestCase(short.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedShortClass(short value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(uint.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(uint.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedUintClass(uint value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(ulong.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(847847645745745U)] + [TestCase(ulong.MaxValue)] + public void ShouldDeserialize_ToStronglyTypedUlongClass(ulong value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildNonString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + public void ShouldDeserialize_ToStronglyTypedUshortClass() + { + var values = new[] { ushort.MinValue, (ushort)0, (ushort)1, (ushort)34, (ushort)7374, ushort.MaxValue }; + // Arrange + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildNonStringArray(stronglyTyped.Select(x => x.TestValue.Value).Cast()); + + // Act + + var result = JsonSerializer.Deserialize>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [TestCase("2020-08-14T14:35:57+0000")] + [TestCase("2020-08-14T14:35:57-1000")] + [TestCase("2020-08-14T14:35:57Z")] + [TestCase("2320-07-21T23:00:35Z")] + [TestCase("1539-05-06T09:20:45Z")] + public void ShouldDeserialize_ToStronglyTypedDateTimeClass(DateTime value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase(TimeSpan.TicksPerMillisecond)] + [TestCase(TimeSpan.TicksPerSecond)] + [TestCase(TimeSpan.TicksPerMinute)] + [TestCase(TimeSpan.TicksPerHour)] + [TestCase(TimeSpan.TicksPerDay)] + public void ShouldDeserialize_ToStronglyTypedTimeSpanClass_FromTicks(long value) + { + var timeSpan = TimeSpan.FromTicks(value); + var expected = XmlConvert.ToString(timeSpan); + + // Arrange + + var stronglyTyped = new SerializationDto(timeSpan); + var json = BuildString(expected); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [TestCase("6")] + [TestCase("6:12")] + [TestCase("6:12:14")] + [TestCase("6:12:14:45")] + [TestCase("6.12:14:45")] + [TestCase("6:12:14:45.3448")] + public void ShouldDeserialize_ToStronglyTypedTimeSpanClass(TimeSpan timeSpan) + { + var expected = XmlConvert.ToString(timeSpan); + + // Arrange + + var stronglyTyped = new SerializationDto(timeSpan); + var json = BuildString(expected); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedEmailClass(Email value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(stronglyTyped.TestValue.Value.Address); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedEmailsClass(IReadOnlyCollection values) + { + // Arrange + + var stronglyTyped = values + .Select(x => new SerializationDto(x)) + .ToArray(); + var json = BuildStringArray(stronglyTyped.Select(x => x.TestValue.Value.Address)); + + // Act + + var result = JsonSerializer.Deserialize>>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.Not.Empty); + Assert.That(result, Has.Exactly(stronglyTyped.Length).Items); + Assert.That(result, Is.All.Matches>(x => stronglyTyped.Any(s => s.TestValue == x.TestValue))); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedIpV4AddressClass(IpV4Address value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedIpV6AddressClass(IpV6Address value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + [Test] + [StrongAutoData] + public void ShouldDeserialize_ToStronglyTypedMacAddressClass(MacAddress value) + { + // Arrange + + var stronglyTyped = new SerializationDto(value); + var json = BuildString(value); + + // Act + + var result = JsonSerializer.Deserialize>(json, JSON_SERIALIZER_SETTINGS); + + // Assert + + Assert.That(result, Is.Not.Null); + Assert.That(result.TestValue, Is.EqualTo(stronglyTyped.TestValue)); + } + + private static string BuildStringArray(IEnumerable values) + { + var stringBuilder = new StringBuilder("[ \n"); + + foreach (var value in values) + { + stringBuilder.AppendFormat(" {0},\n", BuildString(value)); + } + + stringBuilder.Append(']'); + var result = stringBuilder.ToString(); + return result; + } + + private static string BuildNonStringArray(IEnumerable values) + { + var stringBuilder = new StringBuilder("[ \n"); + + foreach (var value in values) + { + stringBuilder.AppendFormat("{0},\n", BuildNonString(value)); + } + + stringBuilder.Append(']'); + var result = stringBuilder.ToString(); + return result; + } + + private static string BuildString(object value) + { + return $"{{ \"testValue\": \"{value?.ToString()?.Replace("\"", "\\\"")}\" }}"; + } + + private static string BuildNonString(object value) + { + return $"{{ \"testValue\": {value} }}"; + } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/SerializationTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/SerializationTests.cs new file mode 100644 index 0000000..be89dd5 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/SystemTextJson/SerializationTests.cs @@ -0,0 +1,686 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Xml; +using NUnit.Framework; +using Xtz.StronglyTyped.BuiltinTypes.AutoFixture; +using Xtz.StronglyTyped.BuiltinTypes.Internet; + +namespace Xtz.StronglyTyped.UnitTests.SystemTextJson +{ + public class SerializationTests + { + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldSerialize_GivenStronglyTypedStringClass(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedString(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("New York")] + [TestCase("New \"The Big Apple\" York")] + public void ShouldSerialize_GivenStronglyTypedStringStruct(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringStruct(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldSerialize_GivenStronglyTypedStringClassAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringAllowEmpty(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("Brazil")] + [TestCase("Trinidad and Tobago")] + [TestCase("")] + public void ShouldSerialize_GivenStronglyTypedStringStructAllowEmpty(string value) + { + // Arrange + + var stronglyTyped = new StronglyTypedStringAllowEmptyStruct(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldSerialize_GivenStronglyTypedGuidClass(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuid(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("57c2a2d3-99cc-4468-998e-f3a3abe089ca")] + public void ShouldSerialize_GivenStronglyTypedGuidStruct(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuidStruct(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + // ReSharper disable once NUnit.IncorrectArgumentType + [Test] + [TestCase("61f6e72c-8db3-4a70-89b6-c3d07dbcce11")] + public void ShouldSerialize_GivenStronglyTypedGuidIdClass(Guid value) + { + // Arrange + + var stronglyTyped = new StronglyTypedGuidId(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntClass(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedInt(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(int.MinValue)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(6372)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntStruct(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedIntStruct(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(1)] + [TestCase(546)] + [TestCase(6474)] + [TestCase(int.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedIntIdClass(int value) + { + // Arrange + + var stronglyTyped = new StronglyTypedIntId(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(false, "false")] + [TestCase(true, "true")] + public void ShouldSerialize_GivenStronglyTypedBoolClass(bool value, string expectedValue) + { + // Arrange + + var stronglyTyped = new StronglyTypedBool(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expectedValue)); + } + + [Test] + [TestCase(byte.MinValue)] + [TestCase(0)] + [TestCase(1)] + [TestCase(233)] + [TestCase(byte.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedByteClass(byte value) + { + // Arrange + + var stronglyTyped = new StronglyTypedByte(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(char.MinValue)] + [TestCase('I')] + [TestCase('x')] + [TestCase('\xF0')] + [TestCase('Ž')] + [TestCase('£')] + [TestCase('¶')] + [TestCase('Ð')] + [TestCase('4')] + [TestCase('ߡ')] + [TestCase('ݓ')] + [TestCase('Ѝ')] + [TestCase(char.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedCharClass(char value) + { + // Arrange + + var stronglyTyped = new StronglyTypedChar(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + //[TestCase(-79228162514264337593543950335m)] + [TestCase(-5745)] + [TestCase(-968.2566)] + //[TestCase(-968.2566m)] + //[TestCase(-1m)] + [TestCase(0)] + //[TestCase(0m)] + [TestCase(1)] + //[TestCase(1m)] + [TestCase(34634)] + [TestCase(6534.353)] + //[TestCase(79228162514264337593543950335m)] + public void ShouldSerialize_GivenStronglyTypedDecimalClass(decimal value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDecimal(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + public void ShouldSerialize_GivenStronglyTypedDecimalClass() + { + // Arrange + + var values = new [] { decimal.MinValue, -968.2566m, decimal.MinusOne, decimal.Zero, decimal.One, decimal.MaxValue }; + + var stronglyTyped = values.Select(x => (StronglyTypedDecimal)x); + var json = JsonSerializer.Serialize(values); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(double.MinValue)] + [TestCase(double.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353)] + [TestCase(double.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedDoubleClass(double value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDouble(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(float.MinValue)] + [TestCase(float.Epsilon)] + [TestCase(-5745)] + [TestCase(-968.2566F)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(6534.353F)] + [TestCase(float.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedFloatClass(float value) + { + // Arrange + + var stronglyTyped = new StronglyTypedFloat(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(long.MinValue)] + [TestCase(-5745)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34634)] + [TestCase(41343252352352)] + [TestCase(long.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedLongClass(long value) + { + // Arrange + + var stronglyTyped = new StronglyTypedLong(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(sbyte.MinValue)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(sbyte.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedSbyteClass(sbyte value) + { + // Arrange + + var stronglyTyped = new StronglyTypedSbyte(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(short.MinValue)] + [TestCase(-24633)] + [TestCase(-55)] + [TestCase(0)] + [TestCase(1)] + [TestCase(34)] + [TestCase(7374)] + [TestCase(short.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedShortClass(short value) + { + // Arrange + + var stronglyTyped = new StronglyTypedShort(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(uint.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(uint.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedUintClass(uint value) + { + // Arrange + + var stronglyTyped = new StronglyTypedUint(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(ulong.MinValue)] + [TestCase(0U)] + [TestCase(1U)] + [TestCase(34U)] + [TestCase(7374U)] + [TestCase(45745745U)] + [TestCase(847847645745745U)] + [TestCase(ulong.MaxValue)] + public void ShouldSerialize_GivenStronglyTypedUlongClass(ulong value) + { + // Arrange + + var stronglyTyped = new StronglyTypedUlong(value); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + public void ShouldSerialize_GivenStronglyTypedUshortClass() + { + // Arrange + + var values = new ushort[] { ushort.MinValue, 0, 1, 34, 7374, ushort.MaxValue }; + + var stronglyTyped = values.Select(x => (StronglyTypedUshort)x); + var json = JsonSerializer.Serialize(values); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase("2020-08-14T14:35:57+0000")] + [TestCase("2020-08-14T14:35:57-1000")] + [TestCase("2020-08-14T14:35:57Z")] + [TestCase("2320-07-21T23:00:35Z")] + [TestCase("1539-05-06T09:20:45Z")] + public void ShouldSerialize_GivenStronglyTypedDateTimeClass(DateTime value) + { + // Arrange + + var stronglyTyped = new StronglyTypedDateTime(value); + var json = JsonSerializer.Serialize(value.ToUniversalTime()); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [TestCase(TimeSpan.TicksPerMillisecond)] + [TestCase(TimeSpan.TicksPerSecond)] + [TestCase(TimeSpan.TicksPerMinute)] + [TestCase(TimeSpan.TicksPerHour)] + [TestCase(TimeSpan.TicksPerDay)] + public void ShouldSerialize_GivenStronglyTypedTimeSpanClass_FromTicks(long value) + { + // Arrange + + var timeSpan = TimeSpan.FromTicks(value); + var stronglyTyped = new StronglyTypedTimeSpan(timeSpan); + var expected = $"\"{XmlConvert.ToString(stronglyTyped)}\""; + var expectedString = $"\"{stronglyTyped}\""; + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result, Is.EqualTo(expectedString)); + } + + [Test] + [TestCase("6")] + [TestCase("6:12")] + [TestCase("6:12:14")] + [TestCase("6:12:14:45")] + [TestCase("6.12:14:45")] + [TestCase("6:12:14:45.3448")] + public void ShouldSerialize_GivenStronglyTypedTimeSpanClass(TimeSpan value) + { + // Arrange + + var stronglyTyped = new StronglyTypedTimeSpan(value); + var expected = $"\"{XmlConvert.ToString(value)}\""; + var expectedString = $"\"{stronglyTyped}\""; + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result, Is.EqualTo(expectedString)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedEmailClass(Email stronglyTyped) + { + // Arrange + + var json = JsonSerializer.Serialize(stronglyTyped.Value.Address); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedEmailsClass(IReadOnlyCollection stronglyTyped) + { + // Arrange + + var value = stronglyTyped.Select(x => x.Value.Address); + var json = JsonSerializer.Serialize(value); + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(json)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedIpV4AddressClass(IpV4Address stronglyTyped) + { + // Arrange + + var expected = $"\"{stronglyTyped.Value}\""; + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedIpV6AddressClass(IpV6Address stronglyTyped) + { + // Arrange + + var expected = $"\"{stronglyTyped.Value}\""; + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + [StrongAutoData] + public void ShouldSerialize_GivenStronglyTypedMacAddressClass(MacAddress stronglyTyped) + { + // Arrange + + var expectedToString = $"\"{stronglyTyped.Value}\""; + var expected = $"\"{stronglyTyped.ToString(MacAddress.Separator.Hyphen)}\""; + + // Act + + var result = JsonSerializer.Serialize(stronglyTyped); + + // Assert + + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Replace("-", string.Empty), Is.EqualTo(expectedToString)); + } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/AbsoluteUriTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/AbsoluteUriTests.cs index 7cbaf74..4531f96 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/AbsoluteUriTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/AbsoluteUriTests.cs @@ -26,8 +26,8 @@ public void TypeConverter_ShouldParseGenericStronglyTyped_GivenString() //// Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result); - Assert.AreEqual(expected.Value, result.Value); + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Value, Is.EqualTo(expected.Value)); } [Test] @@ -48,8 +48,8 @@ public void TypeConverter_ShouldParseStronglyTyped_GivenInnerType() //// Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result); - Assert.AreEqual(expected.Value, result.Value); + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Value, Is.EqualTo(expected.Value)); } [Test] diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/BoolTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/BoolTests.cs new file mode 100644 index 0000000..604c685 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/BoolTests.cs @@ -0,0 +1,32 @@ +using System.ComponentModel; +using NUnit.Framework; + +namespace Xtz.StronglyTyped.UnitTests.TypeConverters +{ + public class BoolTests + { + [Test] + public void TypeConverter_ShouldParseStronglyTyped_GivenBool() + { + //// Arrange + + var value = true; + var strongType = typeof(StronglyTypedBool); + var typeConverter = TypeDescriptor.GetConverter(strongType); + + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + var expected = new StronglyTypedBool(value); + + //// Act + + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + var result = typeConverter.ConvertFrom(value) as StronglyTypedBool; + + //// Assert + + Assert.IsNotNull(result); + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Value, Is.EqualTo(expected.Value)); + } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/EmailTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/EmailTests.cs index 9820672..c9bbe83 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/EmailTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/EmailTests.cs @@ -27,7 +27,7 @@ public void TypeConverter_ShouldParseEmail_GivenString(string value) //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("john.doe@example.com", "JOHN.DOE@EXAMPLE.COM")] @@ -50,7 +50,7 @@ public void Email_ShouldBeEqual_GivenSameStringsDifferentCasing(string value, st //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/IntTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/IntTests.cs index 4d399a8..a10f5a2 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/IntTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/IntTests.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using NUnit.Framework; using Xtz.StronglyTyped.TypeConverters; @@ -24,8 +25,8 @@ public void TypeConverter_ShouldParseStronglyTyped_GivenInt32() //// Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result); - Assert.AreEqual(expected.Value, result.Value); + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Value, Is.EqualTo(expected.Value)); } [TestCase(int.MinValue)] @@ -41,11 +42,12 @@ public void TypeConverter_ShouldThrow_GivenInvalidInt32(int value) //// Act - TestDelegate action = () => typeConverter.ConvertFrom(value); + [ExcludeFromCodeCoverage] + void Action() => typeConverter.ConvertFrom(value); //// Assert - Assert.Throws(action); + Assert.Throws(Action); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/MacAddressTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/MacAddressTests.cs index c495953..6fee8b3 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/MacAddressTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/MacAddressTests.cs @@ -31,7 +31,7 @@ public void TypeConverter_ShouldParseStronglyTyped_GivenString(string value) //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("00:11:22:33:44:55")] @@ -58,7 +58,7 @@ public void TypeConverter_ShouldParseWrappingStronglyTyped_GivenInnerType(string //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("00:11:22:33:44:55")] @@ -85,34 +85,7 @@ public void TypeConverter_ShouldConvertToString_GivenStronglyTyped(string value) //// Assert - Assert.AreEqual(expected, result); - } - - [TestCase("00:11:22:33:44:55")] - [TestCase("00-11-22-33-44-55")] - [TestCase("A0:A1:A2:A3:A4:A5")] - [TestCase("A0-A1-A2-A3-A4-A5")] - [TestCase("554433221100")] - [TestCase("ffeeddbbccaa")] - [TestCase("FFEEDDBBCCAA")] - [Test] - public void TypeConverter_ShouldConvertToString_WhenImplicitlyCastedToString(string value) - { - //// Arrange - - var stronglyTypedValue = new MacAddress(PhysicalAddress.Parse(ValueToString(value))); - var strongType = typeof(MacAddress); - var typeConverter = TypeDescriptor.GetConverter(strongType); - - var expected = ValueToString(value); - - //// Act - - var result = typeConverter.ConvertToString(stronglyTypedValue); - - //// Assert - - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } private static string ValueToString(string value) diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/StringTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/StringTests.cs index ed3f409..5b50ef0 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/StringTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/TypeConverters/StringTests.cs @@ -23,7 +23,7 @@ public void TypeConverter_ShouldParseStronglyTyped_GivenString() //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [Test] @@ -37,11 +37,12 @@ public void TypeConverter_ShouldReturnNull_GivenNull() //// Act + // ReSharper disable once ExpressionIsAlwaysNull var result = typeConverter.ConvertFrom(value); //// Assert - Assert.IsNull(result); + Assert.That(result, Is.Null); } [Test] @@ -61,7 +62,7 @@ public void TypeConverter_ShouldSerializeToString_GivenStronglyTyped() //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase("Sweden")] diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/ConversionTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/ConversionTests.cs index 0f4f771..79da088 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/ConversionTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/ConversionTests.cs @@ -1,5 +1,4 @@ -using System; -using NUnit.Framework; +using NUnit.Framework; namespace Xtz.StronglyTyped.UnitTests.Values { @@ -21,7 +20,7 @@ public void ShouldCreateEmployeeIntId_GivenInt_WhenExplicitlyConverted(int value //// Assert - Assert.AreEqual(expected, result); + Assert.That(result, Is.EqualTo(expected)); } [TestCase(-123)] @@ -40,7 +39,7 @@ public void ShouldConvertToInt_GivenEmployeeIntId_WhenExplicitlyConverted(int va //// Assert - Assert.AreEqual(value, result); + Assert.That(result, Is.EqualTo(value)); } [TestCase(-123)] @@ -59,26 +58,7 @@ public void ShouldConvertToInt_GivenEmployeeIntId_WhenImplicitlyConverted(int va //// Assert - Assert.AreEqual(value, result); - } - - [TestCase(-123)] - [TestCase(0)] - [TestCase(3697)] - [Test] - public void Convert_ShouldConvertToInt_GivenStronglyTyped_WhenConvertingFromObject(int value) - { - //// Arrange - - var stronglyTyped = new EmployeeIntId(value); - - //// Act - - var result = Convert.ToInt32(stronglyTyped); - - //// Assert - - Assert.AreEqual(value, result); + Assert.That(result, Is.EqualTo(value)); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/CreationTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/CreationTests.cs index 419dded..0560ae5 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/CreationTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/CreationTests.cs @@ -23,7 +23,7 @@ public void ShouldCreate_GivenInt(int value) //// Assert - Assert.AreEqual(value, result.Value); + Assert.That(result.Value, Is.EqualTo(value)); } [TestCase(Int32.MinValue)] @@ -44,7 +44,7 @@ public void ShouldReturnInnerValue_WhenToString(int value) //// Assert - Assert.AreEqual(expected, stronglyTyped.ToString()); + Assert.That(stronglyTyped.ToString(), Is.EqualTo(expected)); } [TestCase(null)] @@ -57,6 +57,7 @@ public void ShouldThrow_GivenNullOrEmpty(string country) //// Act + // ReSharper disable once ObjectCreationAsStatement [ExcludeFromCodeCoverage] void Action() => new Country(country); @@ -74,8 +75,11 @@ public void ShouldThrow_GivenNull_ForAllowEmpty() //// Act + // ReSharper disable once ObjectCreationAsStatement + // ReSharper disable once ExpressionIsAlwaysNull + // ReSharper disable once AssignNullToNotNullAttribute [ExcludeFromCodeCoverage] - void Action() => new CountryAllowingEmpty(value); + void Action() => new StronglyTypedStringAllowEmpty(value); //// Assert @@ -91,13 +95,13 @@ public void ShouldCreate_GivenEmpty_ForAllowEmpty() //// Act - var result = new CountryAllowingEmpty(value); + var result = new StronglyTypedStringAllowEmpty(value); //// Assert - Assert.NotNull(result); + Assert.That(result, Is.Not.Null); Assert.IsEmpty(result.Value); - Assert.IsEmpty(value.ToString()); + Assert.IsEmpty(value); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityOperatorsTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityOperatorsTests.cs index faf05bc..ce28132 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityOperatorsTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityOperatorsTests.cs @@ -16,10 +16,7 @@ public void EqualsOperator_ShouldBeTrue_ForSameStronglyTypedValues() //// Assert -#pragma warning disable CS1718 // Comparison made to same variable - // ReSharper disable once EqualExpressionComparison - Assert.IsTrue(value == value); -#pragma warning restore CS1718 // Comparison made to same variable + Assert.That(value == value, Is.True); } [Test] @@ -35,8 +32,8 @@ public void EqualsOperator_ShouldBeTrue_ForSameValuesStronglyTypedAndObject() //// Assert - Assert.IsTrue(value == objValue); - Assert.IsTrue(objValue == value); + Assert.That(value == objValue, Is.True); + Assert.That(objValue == value, Is.True); } [Test] @@ -47,12 +44,12 @@ public void EqualsOperator_ShouldBeFalse_ForStronglyTypedValue_AndSameString() //// Act var value1 = new Country("Norway"); - var value2 = "Norway"; + const string value2 = "Norway"; //// Assert - Assert.IsFalse(value1 == value2); - Assert.IsFalse(value2 == value1); + Assert.That(value1 == value2, Is.False); + Assert.That(value2 == value1, Is.False); } [Test] @@ -67,8 +64,8 @@ public void EqualsOperator_ShouldBeTrue_ForStronglyTypedValues_GivenSameStrings( //// Assert - Assert.IsTrue(value1 == value2); - Assert.IsTrue(value2 == value1); + Assert.That(value1 == value2, Is.True); + Assert.That(value2 == value1, Is.True); } [Test] @@ -83,8 +80,8 @@ public void EqualsOperator_ShouldBeTrue_ForStronglyTypedAndObject_GivenSameStrin //// Assert - Assert.IsTrue(value == objValue); - Assert.IsTrue(objValue == value); + Assert.That(value == objValue, Is.True); + Assert.That(objValue == value, Is.True); } [Test] @@ -99,8 +96,8 @@ public void EqualsOperator_ShouldBeFalse_ForStronglyTypedValues_GivenDifferentSt //// Assert - Assert.IsFalse(value1 == value2); - Assert.IsFalse(value2 == value1); + Assert.That(value1 == value2, Is.False); + Assert.That(value2 == value1, Is.False); } [Test] @@ -115,8 +112,8 @@ public void EqualsOperator_ShouldBeFalse_ForStronglyTypedAndObject_GivenDifferen //// Assert - Assert.IsFalse(value == objValue); - Assert.IsFalse(objValue == value); + Assert.That(value == objValue, Is.False); + Assert.That(objValue == value, Is.False); } [Test] @@ -131,8 +128,8 @@ public void NotEqualsOperator_ShouldBeFalse_ForStronglyTypedValues_GivenSameStri //// Assert - Assert.IsFalse(value1 != value2); - Assert.IsFalse(value2 != value1); + Assert.That(value1 != value2, Is.False); + Assert.That(value2 != value1, Is.False); } [Test] @@ -147,8 +144,8 @@ public void NotEqualsOperator_ShouldBeFalse_ForStronglyTypedAndObject_GivenSameS //// Assert - Assert.IsFalse(value != objValue); - Assert.IsFalse(objValue != value); + Assert.That(value != objValue, Is.False); + Assert.That(objValue != value, Is.False); } [Test] @@ -163,8 +160,8 @@ public void NotEqualsOperator_ShouldBeTrue_ForStronglyTypedValues_GivenDifferent //// Assert - Assert.IsTrue(value1 != value2); - Assert.IsTrue(value2 != value1); + Assert.That(value1 != value2, Is.True); + Assert.That(value2 != value1, Is.True); } [Test] @@ -179,8 +176,8 @@ public void NotEqualsOperator_ShouldBeTrue_ForStronglyTypedAndObject_GivenDiffer //// Assert - Assert.IsTrue(value != objValue); - Assert.IsTrue(objValue != value); + Assert.That(value != objValue, Is.True); + Assert.That(objValue != value, Is.True); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityTests.cs index 700d391..d26198a 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/EqualityTests.cs @@ -17,8 +17,8 @@ public void StronglyTypedValues_ShouldBeEqual_GivenSameInts(int value) //// Assert - Assert.AreEqual(result1, result2); - Assert.AreEqual(result1.Value, result2.Value); + Assert.That(result2, Is.EqualTo(result1)); + Assert.That(result2.Value, Is.EqualTo(result1.Value)); } [TestCase(27, 45)] @@ -34,8 +34,8 @@ public void StronglyTypedValues_ShouldBeNotEqual_GivenDifferentInts(int value1, //// Assert - Assert.AreNotEqual(result1, result2); - Assert.AreNotEqual(result1.Value, result2.Value); + Assert.That(result2, Is.Not.EqualTo(result1)); + Assert.That(result2.Value, Is.Not.EqualTo(result1.Value)); } [TestCase(22, 11)] @@ -51,8 +51,8 @@ public void ShouldBeEqual_GivenTheSameCalculatedInts(int value1, int value2) //// Assert - Assert.AreEqual(result1, result2); - Assert.AreEqual(result1.Value, result2.Value); + Assert.That(result2, Is.EqualTo(result1)); + Assert.That(result2.Value, Is.EqualTo(result1.Value)); } [TestCase(27)] @@ -68,7 +68,7 @@ public void GetHastCode_ShouldBeEqual_GivenSameInts(int value) //// Assert - Assert.AreEqual(result1.GetHashCode(), result2.GetHashCode()); + Assert.That(result2.GetHashCode(), Is.EqualTo(result1.GetHashCode())); } [TestCase(27, 45)] @@ -84,7 +84,7 @@ public void GetHastCode_ShouldBeNotEqual_GivenDifferentInts(int value1, int valu //// Assert - Assert.AreNotEqual(result1.GetHashCode(), result2.GetHashCode()); + Assert.That(result2.GetHashCode(), Is.Not.EqualTo(result1.GetHashCode())); } } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/TypeConverterTests.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/TypeConverterTests.cs index ee19d76..3d6e7ad 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Values/TypeConverterTests.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Values/TypeConverterTests.cs @@ -26,8 +26,8 @@ public void TypeConverter_ShouldParseStronglyTyped_GivenInt32() //// Assert Assert.IsNotNull(result); - Assert.AreEqual(expected, result); - Assert.AreEqual(expected.Value, result.Value); + Assert.That(result, Is.EqualTo(expected)); + Assert.That(result.Value, Is.EqualTo(expected.Value)); } [TestCase(Int32.MinValue)] diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/Xtz.StronglyTyped.UnitTests.csproj b/src/Tests/Xtz.StronglyTyped.UnitTests/Xtz.StronglyTyped.UnitTests.csproj index 3a9d704..794c282 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/Xtz.StronglyTyped.UnitTests.csproj +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/Xtz.StronglyTyped.UnitTests.csproj @@ -2,7 +2,7 @@ net5 - 9 + preview @@ -15,13 +15,27 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryId.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryId.cs index 3145f5c..5f62946 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryId.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryId.cs @@ -1,103 +1,10 @@ -using System; -using System.ComponentModel; -using Xtz.StronglyTyped.TypeConverters; +using Xtz.StronglyTyped.SourceGenerator; namespace Xtz.StronglyTyped.UnitTests { - // TODO: Replace by auto-generated class with [StrongType(typeof(int))] - [TypeConverter(typeof(TypeConverter))] - public class CountryId : StronglyTyped, IConvertible + [StrongType(typeof(int))] + public partial class CountryId { - public CountryId(int value) - : base(value) - { - } - - public TypeCode GetTypeCode() - { - return Value.GetTypeCode(); - } - - public bool ToBoolean(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Boolean)}'"); - } - - public byte ToByte(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Byte)}'"); - } - - public char ToChar(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Char)}'"); - } - - public DateTime ToDateTime(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(DateTime)}'"); - } - - public decimal ToDecimal(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Decimal)}'"); - } - - public double ToDouble(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Double)}'"); - } - - public short ToInt16(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Int16)}'"); - } - - public int ToInt32(IFormatProvider provider) - { - return Value; - } - - public long ToInt64(IFormatProvider provider) - { - return Value; - } - - public sbyte ToSByte(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(SByte)}'"); - } - - public float ToSingle(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(Single)}'"); - } - - public string ToString(IFormatProvider provider) - { - return Value.ToString(provider); - } - - public object ToType(Type conversionType, IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{conversionType}'"); - } - - public ushort ToUInt16(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(UInt16)}'"); - } - - public uint ToUInt32(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(UInt32)}'"); - } - - public ulong ToUInt64(IFormatProvider provider) - { - throw new InvalidCastException($"'{nameof(CountryId)}' is not convertible to '{nameof(UInt64)}'"); - } - protected override bool IsValid(int value) { // ID must be greater than 0 diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/EmployeeIntId.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/EmployeeIntId.cs index ced73e7..f2fd2ae 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/EmployeeIntId.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/EmployeeIntId.cs @@ -1,32 +1,9 @@ -using System.ComponentModel; -using Xtz.StronglyTyped.TypeConverters; +using Xtz.StronglyTyped.SourceGenerator; namespace Xtz.StronglyTyped.UnitTests { - // TODO: Replace by auto-generated struct with [StrongType(typeof(int))] - [TypeConverter(typeof(TypeConverter))] - public struct EmployeeIntId : IStronglyTyped + [StrongType(typeof(int))] + public partial struct EmployeeIntId { - public int Value { get; } - - public EmployeeIntId(int value) - { - Value = value; - } - - public override string ToString() - { - return Value.ToString(); - } - - public static explicit operator EmployeeIntId(int value) - { - return new EmployeeIntId(value); - } - - public static implicit operator int(EmployeeIntId stronglyTyped) - { - return stronglyTyped.Value; - } } } diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/SerializationDto.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/SerializationDto.cs new file mode 100644 index 0000000..d0f1a97 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/SerializationDto.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics; + +namespace Xtz.StronglyTyped.UnitTests +{ + [DebuggerDisplay("{TestValue,nq}")] + public class SerializationDto + where TStronglyTyped : IStronglyTyped + { + public SerializationDto() + { + } + + public SerializationDto(TStronglyTyped stronglyTyped) + { + TestValue = stronglyTyped; + } + + public SerializationDto(object value) + { + TestValue = (TStronglyTyped)Activator.CreateInstance(typeof(TStronglyTyped), value); + } + + public TStronglyTyped TestValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBool.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBool.cs new file mode 100644 index 0000000..657d93a --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBool.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(bool))] + public sealed partial class StronglyTypedBool + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBoolStruct.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBoolStruct.cs new file mode 100644 index 0000000..a920ea9 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedBoolStruct.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(bool), Allow.Empty)] + public partial struct StronglyTypedBoolStruct + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedByte.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedByte.cs new file mode 100644 index 0000000..06acf8c --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedByte.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(byte))] + public sealed partial class StronglyTypedByte + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedChar.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedChar.cs new file mode 100644 index 0000000..622c60a --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedChar.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(char))] + public sealed partial class StronglyTypedChar + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDateTime.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDateTime.cs new file mode 100644 index 0000000..8f30bf5 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDateTime.cs @@ -0,0 +1,10 @@ +using System; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(DateTime))] + public sealed partial class StronglyTypedDateTime + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDecimal.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDecimal.cs new file mode 100644 index 0000000..dfc12ac --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDecimal.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(decimal))] + public sealed partial class StronglyTypedDecimal + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDouble.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDouble.cs new file mode 100644 index 0000000..00611a6 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedDouble.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(double))] + public sealed partial class StronglyTypedDouble + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedFloat.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedFloat.cs new file mode 100644 index 0000000..fc26576 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedFloat.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(float))] + public sealed partial class StronglyTypedFloat + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuid.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuid.cs new file mode 100644 index 0000000..d9d0f23 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuid.cs @@ -0,0 +1,10 @@ +using System; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(Guid))] + public sealed partial class StronglyTypedGuid + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidAllowEmpty.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidAllowEmpty.cs new file mode 100644 index 0000000..dcadd0d --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidAllowEmpty.cs @@ -0,0 +1,10 @@ +using System; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(Guid), Allow.Empty)] + public sealed partial class StronglyTypedGuidAllowEmpty + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidId.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidId.cs new file mode 100644 index 0000000..e785b80 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidId.cs @@ -0,0 +1,11 @@ +using System; +using Xtz.StronglyTyped.BuiltinTypes.Ids; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(Guid))] + public partial class StronglyTypedGuidId : GuidId + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidStruct.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidStruct.cs new file mode 100644 index 0000000..8565e1d --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedGuidStruct.cs @@ -0,0 +1,10 @@ +using System; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(Guid))] + public partial struct StronglyTypedGuidStruct + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedInt.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedInt.cs new file mode 100644 index 0000000..e4b711c --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedInt.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(int))] + public sealed partial class StronglyTypedInt + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntId.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntId.cs new file mode 100644 index 0000000..bfba099 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntId.cs @@ -0,0 +1,10 @@ +using Xtz.StronglyTyped.BuiltinTypes.Ids; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(int))] + public partial class StronglyTypedIntId : IntId + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntStruct.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntStruct.cs new file mode 100644 index 0000000..f53037b --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedIntStruct.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(int))] + public partial struct StronglyTypedIntStruct + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedLong.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedLong.cs new file mode 100644 index 0000000..b511286 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedLong.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(long))] + public sealed partial class StronglyTypedLong + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedSbyte.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedSbyte.cs new file mode 100644 index 0000000..7ce9648 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedSbyte.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(sbyte))] + public sealed partial class StronglyTypedSbyte + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedShort.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedShort.cs new file mode 100644 index 0000000..3a8cc75 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedShort.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(short))] + public sealed partial class StronglyTypedShort + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/City.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedString.cs similarity index 68% rename from src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/City.cs rename to src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedString.cs index eae3bb8..9384ffa 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/City.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedString.cs @@ -3,7 +3,7 @@ namespace Xtz.StronglyTyped.UnitTests { [StrongType] - public sealed partial class City + public sealed partial class StronglyTypedString { } } \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryAllowingEmpty.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmpty.cs similarity index 67% rename from src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryAllowingEmpty.cs rename to src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmpty.cs index ba0ea1f..024989e 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/CountryAllowingEmpty.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmpty.cs @@ -3,7 +3,7 @@ namespace Xtz.StronglyTyped.UnitTests { [StrongType(Allow.Empty)] - public sealed partial class CountryAllowingEmpty + public sealed partial class StronglyTypedStringAllowEmpty { } } diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmptyStruct.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmptyStruct.cs new file mode 100644 index 0000000..1f72ce9 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringAllowEmptyStruct.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(Allow.Empty)] + public partial struct StronglyTypedStringAllowEmptyStruct + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringStruct.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringStruct.cs new file mode 100644 index 0000000..62b5839 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedStringStruct.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType] + public partial struct StronglyTypedStringStruct + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedTimeSpan.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedTimeSpan.cs new file mode 100644 index 0000000..e8848d8 --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedTimeSpan.cs @@ -0,0 +1,10 @@ +using System; +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(TimeSpan))] + public sealed partial class StronglyTypedTimeSpan + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUint.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUint.cs new file mode 100644 index 0000000..746d20f --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUint.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(uint))] + public sealed partial class StronglyTypedUint + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUlong.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUlong.cs new file mode 100644 index 0000000..52820fa --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUlong.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(ulong))] + public sealed partial class StronglyTypedUlong + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUshort.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUshort.cs new file mode 100644 index 0000000..d3139ab --- /dev/null +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/StronglyTypedUshort.cs @@ -0,0 +1,9 @@ +using Xtz.StronglyTyped.SourceGenerator; + +namespace Xtz.StronglyTyped.UnitTests +{ + [StrongType(typeof(ushort))] + public sealed partial class StronglyTypedUshort + { + } +} \ No newline at end of file diff --git a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/UserId.cs b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/UserId.cs index a6840e5..8ebb75e 100644 --- a/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/UserId.cs +++ b/src/Tests/Xtz.StronglyTyped.UnitTests/_TestModels/UserId.cs @@ -1,21 +1,10 @@ using System; -using System.ComponentModel; -using Xtz.StronglyTyped.TypeConverters; +using Xtz.StronglyTyped.SourceGenerator; namespace Xtz.StronglyTyped.UnitTests { - // TODO: Replace by auto-generated class with [StrongType(typeof(int))] - [TypeConverter(typeof(TypeConverter))] - public class UserId : StronglyTyped + [StrongType(typeof(Guid))] + public partial class UserId { - public UserId(Guid value) - : base(value) - { - } - - protected override bool IsValid(Guid value) - { - return value != Guid.Empty; - } } } diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedNewtonsoftConverter.cs b/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedNewtonsoftConverter.cs deleted file mode 100644 index a09efc2..0000000 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/WebApi/StronglyTypedNewtonsoftConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.ComponentModel; -using Newtonsoft.Json; - -namespace Xtz.StronglyTyped.Api_3_1.IntegrationTests.WebApi -{ - public class StronglyTypedNewtonsoftConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return typeof(IStronglyTyped).IsAssignableFrom(objectType); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var stringValue = reader.ReadAsString(); - var typeConverter = TypeDescriptor.GetConverter(objectType); - - return (IStronglyTyped)typeConverter.ConvertFrom(stringValue); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value is null) - { - writer.WriteValue("null"); - return; - } - - var typeConverter = TypeDescriptor.GetConverter(value.GetType()); - - var stringValue = typeConverter.ConvertTo(value, typeof(string)) as string; - writer.WriteValue(stringValue); - } - } -} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj b/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj deleted file mode 100644 index b8584f2..0000000 --- a/src/Xtz.StronglyTyped.Api_3_1.IntegrationTests/Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netcoreapp3.1 - 9 - - - - - - - - - - - - - - - - - - - diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/BaseFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/BaseFakerSpecimenBuilder.cs index fa54ef7..fac223e 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/BaseFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/BaseFakerSpecimenBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Reflection; +using AutoFixture; using AutoFixture.Kernel; using Bogus; @@ -9,19 +10,72 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture { public abstract class BaseFakerSpecimenBuilder : ISpecimenBuilder { + private static readonly int DEFAULT_REPEAT_COUNT = 3; private NoSpecimen NoSpecimen { get; } = new(); protected abstract Dictionary> FakerFactories { get; } + // KLUDGE: Don't be surprised if you run single test without AutoData but it creates test values for other tests (which you are not trying to run at the moment) public object Create(object request, ISpecimenContext context) { if (request is not ParameterInfo parameterInfo) { - return NoSpecimen; + return request switch + { + MultipleRequest {Request: SeededRequest {Request: Type multipleType}} => + CreateArray(multipleType, context), + SeededRequest {Request: Type type} + when type.TryGetSingleGenericTypeArgument(typeof(IEnumerable<>), out var enumerableType) => + CreateEnumerable(enumerableType, context), + _ => NoSpecimen + }; } var parameterType = parameterInfo.ParameterType; + return Create(parameterType); + } + + private object CreateEnumerable(Type? enumerableType, ISpecimenContext context) + { + if (enumerableType is null) return NoSpecimen; + + var specimen = context.Resolve(new MultipleRequest(new SeededRequest(enumerableType, null))); + if (specimen is OmitSpecimen) return specimen; + + var typedAdapterType = typeof(ConvertedEnumerable<>).MakeGenericType(enumerableType); + return Activator.CreateInstance(typedAdapterType, specimen); + } + + private object CreateArray(Type multipleType, ISpecimenContext context) + { + var firstElement = Create(multipleType); + if (firstElement is NoSpecimen) return firstElement; + + var count = DEFAULT_REPEAT_COUNT; + if (context is SpecimenContext {Builder: Fixture fixture}) + { + count = fixture.RepeatCount; + if (count < 1) + { + count = DEFAULT_REPEAT_COUNT; + } + } + + var result = new object[count]; + result[0] = firstElement; + for (var i = 1; i < count; i++) + { + result[i] = Create(multipleType); + } + + return result; + } + + private object Create(Type? parameterType) + { + if (parameterType is null) return NoSpecimen; + var fakerObject = GetFaker(parameterType); if (fakerObject == null) return NoSpecimen; diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/ConvertedEnumerable.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/ConvertedEnumerable.cs new file mode 100644 index 0000000..02078d2 --- /dev/null +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/ConvertedEnumerable.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture +{ + public class ConvertedEnumerable : IEnumerable + { + private readonly IEnumerable _enumerable; + + public ConvertedEnumerable(IEnumerable enumerable) + { + _enumerable = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); + } + + public IEnumerator GetEnumerator() + { + foreach (var item in _enumerable) + { + if (item is T variable) yield return variable; + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/TypeExtensions.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/TypeExtensions.cs new file mode 100644 index 0000000..a8b321c --- /dev/null +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Abstract/TypeExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Reflection; + +namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture +{ + public static class TypeExtensions + { + public static bool TryGetSingleGenericTypeArgument( + this Type currentType, + Type expectedGenericDefinition, + out Type? enumerableType) + { + if (!expectedGenericDefinition.GetTypeInfo().IsGenericTypeDefinition) throw new ArgumentException("Must be a generic type definition", nameof(expectedGenericDefinition)); + + var typeInfo = currentType.GetTypeInfo(); + if (typeInfo.IsGenericType && currentType.GetGenericTypeDefinition() == expectedGenericDefinition) + { + var typeArguments = typeInfo.GenericTypeArguments; + if (typeArguments.Length == 1) + { + enumerableType = typeArguments[0]; + return true; + } + } + + enumerableType = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/AddressFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/AddressFakerSpecimenBuilder.cs index d4ff81c..1ee859a 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/AddressFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/AddressFakerSpecimenBuilder.cs @@ -9,7 +9,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders // TODO: Add integration tests to check whether all types are included to the builders public class AddressFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly AddressFakerBuilder _builder = new(true); + private readonly AddressFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CommerceFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CommerceFakerSpecimenBuilder.cs index f2b16c9..6950be9 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CommerceFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CommerceFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class CommerceFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly CommerceFakerBuilder _builder = new(true); + private readonly CommerceFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CompanyFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CompanyFakerSpecimenBuilder.cs index 7abe672..505a42c 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CompanyFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/CompanyFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class CompanyFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly CompanyFakerBuilder _builder = new(true); + private readonly CompanyFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/FinanceFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/FinanceFakerSpecimenBuilder.cs index fcad81f..d2cc764 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/FinanceFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/FinanceFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class FinanceFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly FinanceFakerBuilder _builder = new(true); + private readonly FinanceFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/IdFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/IdFakerSpecimenBuilder.cs index 431ff6e..0571abc 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/IdFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/IdFakerSpecimenBuilder.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using AutoFixture.Kernel; @@ -13,7 +12,7 @@ public class IdFakerSpecimenBuilder : ISpecimenBuilder { private NoSpecimen NoSpecimen { get; } = new(); - private readonly IdFakerBuilder _builder = new(true); + private readonly IdFakerBuilder _builder = new(); private readonly MethodInfo _buildGuidIdFakerMethod; diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/InternetFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/InternetFakerSpecimenBuilder.cs index 6bdd8c3..d8ef3d2 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/InternetFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/InternetFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class InternetFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly InternetFakerBuilder _builder = new(true); + private readonly InternetFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/NameFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/NameFakerSpecimenBuilder.cs index e3c6e18..3d0294a 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/NameFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/NameFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class NameFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly NameFakerBuilder _builder = new(true); + private readonly NameFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/PhoneFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/PhoneFakerSpecimenBuilder.cs index 522f3b6..2743aa6 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/PhoneFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/PhoneFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class PhoneFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly PhoneFakerBuilder _builder = new(true); + private readonly PhoneFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/VehicleFakerSpecimenBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/VehicleFakerSpecimenBuilder.cs index d2fb57c..fd87aa8 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/VehicleFakerSpecimenBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Builders/VehicleFakerSpecimenBuilder.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture.Builders { public class VehicleFakerSpecimenBuilder : BaseFakerSpecimenBuilder { - private readonly VehicleFakerBuilder _builder = new(true); + private readonly VehicleFakerBuilder _builder = new(); protected override Dictionary> FakerFactories => new() { diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/StrongAutoDataAttribute.cs b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/StrongAutoDataAttribute.cs index 1301230..cd5b116 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/StrongAutoDataAttribute.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/StrongAutoDataAttribute.cs @@ -8,12 +8,19 @@ namespace Xtz.StronglyTyped.BuiltinTypes.AutoFixture [AttributeUsage(AttributeTargets.Method)] public class StrongAutoDataAttribute : AutoDataAttribute { + private static readonly Lazy FIXTURE = new(BuildFixture); + public StrongAutoDataAttribute() - : base(CreateFixture) + : base(FixtureFunc) + { + } + + private static IFixture FixtureFunc() { + return FIXTURE.Value; } - private static IFixture CreateFixture() + private static IFixture BuildFixture() { var fixture = new Fixture(); fixture.Customizations.Add(new AddressFakerSpecimenBuilder()); diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Xtz.StronglyTyped.BuiltinTypes.AutoFixture.csproj b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Xtz.StronglyTyped.BuiltinTypes.AutoFixture.csproj index 03aa0ab..8a19b8a 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Xtz.StronglyTyped.BuiltinTypes.AutoFixture.csproj +++ b/src/Xtz.StronglyTyped.BuiltinTypes.AutoFixture/Xtz.StronglyTyped.BuiltinTypes.AutoFixture.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.BuiltinTypes.AutoFixture - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,6 +33,11 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + @@ -40,11 +45,36 @@ Make compiler your friend, introduce semantics to your code. + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Abstract/BaseFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Abstract/BaseFakerBuilder.cs index 59818b0..574e8ca 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Abstract/BaseFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Abstract/BaseFakerBuilder.cs @@ -6,9 +6,9 @@ namespace Xtz.StronglyTyped.BuiltinTypes.Bogus { public abstract class BaseFakerBuilder { - private static readonly MemoryCacheEntryOptions MemoryCacheEntryOptions = new() { Size = 1 }; + private static readonly MemoryCacheEntryOptions MEMORY_CACHE_ENTRY_OPTIONS = new() { Size = 1 }; - private static readonly MemoryCache Cache = new(new MemoryCacheOptions { SizeLimit = 500 }); + private static readonly MemoryCache CACHE = new(new MemoryCacheOptions { SizeLimit = 500 }); private readonly bool _useFakerCache; @@ -30,14 +30,14 @@ public Faker GetFaker(Func> fakerFactory, string? ? $"{typeof(TValue).FullName}_{cacheKey}" : typeof(TValue).FullName; - var cachedValue = Cache.Get(key); + var cachedValue = CACHE.Get(key); if (cachedValue != null) { return (cachedValue as Faker)!; } var result = fakerFactory(); - Cache.Set(key, result, MemoryCacheEntryOptions); + CACHE.Set(key, result, MEMORY_CACHE_ENTRY_OPTIONS); return result; } } diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CommerceFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CommerceFakerBuilder.cs index b1fb556..0b38f21 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CommerceFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CommerceFakerBuilder.cs @@ -98,7 +98,7 @@ public Faker BuildProductMaterialFaker() public Faker BuildProductFullNameFaker() { var result = GetFaker(() => new Faker() - .CustomInstantiator(f => + .CustomInstantiator(_ => { var productAdjective = BuildProductAdjectiveFaker().Generate(); var productMaterial = BuildProductMaterialFaker().Generate(); diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CompanyFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CompanyFakerBuilder.cs index 77aac2f..c9243f6 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CompanyFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/CompanyFakerBuilder.cs @@ -5,7 +5,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.Bogus { public class CompanyFakerBuilder : BaseFakerBuilder { - private CommerceFakerBuilder _commerceFakerBuilder; + private readonly CommerceFakerBuilder _commerceFakerBuilder; public CompanyFakerBuilder(bool useFakerCache = true) : base(useFakerCache) diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/FakerBuilderException.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/FakerBuilderException.cs index 85692ef..41b1883 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/FakerBuilderException.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/FakerBuilderException.cs @@ -1,16 +1,28 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped.BuiltinTypes.Bogus { [ExcludeFromCodeCoverage] + [Serializable] public class FakerBuilderException : ApplicationException { - public FakerBuilderException(string message) : base(message) + public FakerBuilderException(string message) + : base(message) { } - public FakerBuilderException(string message, Exception innerException) : base(message, innerException) + public FakerBuilderException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Constructor is used for deserialization. + /// + protected FakerBuilderException(SerializationInfo info, StreamingContext context) + : base(info, context) { } } diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/GlobalSuppressions.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/GlobalSuppressions.cs new file mode 100644 index 0000000..0feb075 --- /dev/null +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.BuiltinTypes.Bogus.FakerBuilderException")] diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/IdFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/IdFakerBuilder.cs index 6237972..88bc889 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/IdFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/IdFakerBuilder.cs @@ -29,6 +29,7 @@ public Faker BuildIntIdFaker() where TIntId : IntId { var result = GetFaker(() => new Faker() + // ReSharper disable once RedundantArgumentDefaultValue .CustomInstantiator(f => (TIntId)Activator.CreateInstance(typeof(TIntId), f.Random.Int(1, int.MaxValue)))); return result; } diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/InternetFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/InternetFakerBuilder.cs index 198f0f3..919253e 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/InternetFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/InternetFakerBuilder.cs @@ -22,7 +22,9 @@ public Faker BuildAbsoluteUriFaker(WebsiteProtocol? protocol = null var cacheKey = $"{protocol}|{domain}|{fileExt}"; var result = GetFaker(() => new Faker() +#pragma warning disable 8604 .CustomInstantiator(f => new AbsoluteUri(f.Internet.UrlWithPath(protocol, domain, fileExt))), cacheKey); +#pragma warning restore 8604 return result; } @@ -64,7 +66,9 @@ public Faker BuildEmailFaker(FirstName? firstName = null, LastName? lastN var cacheKey = $"{firstName}|{lastName}|{provider}|{uniqueSuffix}"; var result = GetFaker(() => new Faker() +#pragma warning disable CS8604 // Possible null reference argument. .CustomInstantiator(f => new Email(f.Internet.Email(firstName, lastName, provider, uniqueSuffix))), cacheKey); +#pragma warning restore CS8604 // Possible null reference argument. return result; } @@ -78,7 +82,9 @@ public Faker BuildExampleEmailFaker(FirstName? firstName = null, L var cacheKey = $"{firstName}|{lastName}"; var result = GetFaker(() => new Faker() +#pragma warning disable CS8604 // Possible null reference argument. .CustomInstantiator(f => new ExampleEmail(f.Internet.ExampleEmail(firstName, lastName))), cacheKey); +#pragma warning restore CS8604 // Possible null reference argument. return result; } @@ -165,7 +171,9 @@ public Faker BuildUserNameFaker(FirstName? firstName = null, LastName? var cacheKey = $"{firstName}|{lastName}"; var result = GetFaker(() => new Faker() +#pragma warning disable CS8604 // Possible null reference argument. .CustomInstantiator(f => new UserName(f.Internet.UserName(firstName, lastName))), cacheKey); +#pragma warning restore CS8604 // Possible null reference argument. return result; } diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/NameFakerBuilder.cs b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/NameFakerBuilder.cs index 2c6ce12..6c65e1c 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/NameFakerBuilder.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/NameFakerBuilder.cs @@ -20,7 +20,7 @@ public Faker BuildDisplayNameFaker(string locale = "en", Gender? ge var cacheKey = $"{locale}|{gender}"; var result = GetFaker(() => new Faker() - .CustomInstantiator(f => + .CustomInstantiator(_ => { var fullName = BuildFullNameFaker(locale, gender).Generate(); return new DisplayName($"{fullName.FirstName} {fullName.LastName}"); diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj index 3994eb2..bf2f982 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.BuiltinTypes.Bogus - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,18 +33,50 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj.DotSettings b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj.DotSettings index cd122a4..da8409b 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj.DotSettings +++ b/src/Xtz.StronglyTyped.BuiltinTypes.Bogus/Xtz.StronglyTyped.BuiltinTypes.Bogus.csproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/Price.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/Price.cs index 85e79b6..83313d3 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/Price.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/Price.cs @@ -1,9 +1,14 @@ -using Xtz.StronglyTyped.BuiltinTypes.Finance; +using System.Diagnostics; +using Xtz.StronglyTyped.BuiltinTypes.Finance; namespace Xtz.StronglyTyped.BuiltinTypes.Commerce { /// /// Price. /// - public record Price(Amount Amount, Currency Currency); + [DebuggerDisplay("{ToString(),nq}")] + public record Price(Amount Amount, Currency Currency) + { + public override string ToString() => $"{Amount} {Currency.Code}"; + } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/ProductFullName.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/ProductFullName.cs index 3695210..047a834 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/ProductFullName.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Commerce/ProductFullName.cs @@ -1,9 +1,14 @@ -namespace Xtz.StronglyTyped.BuiltinTypes.Commerce +using System.Diagnostics; + +namespace Xtz.StronglyTyped.BuiltinTypes.Commerce { - // TODO: Add `[DebuggerDisplay]` and `.ToString()` to all records /// /// Product full name. /// /// {Adjective} {Material} {Name} - public record ProductFullName(ProductAdjective ProductAdjective, ProductMaterial ProductMaterial, ProductShortName ProductShortName); + [DebuggerDisplay("{ToString(),nq}")] + public record ProductFullName(ProductAdjective ProductAdjective, ProductMaterial ProductMaterial, ProductShortName ProductShortName) + { + public override string ToString() => $"{ProductAdjective} {ProductMaterial} {ProductShortName}"; + } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Finance/Currency/Currency.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Finance/Currency/Currency.cs index 32e2d64..a4db0c0 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Finance/Currency/Currency.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Finance/Currency/Currency.cs @@ -1,8 +1,13 @@ -namespace Xtz.StronglyTyped.BuiltinTypes.Finance +using System.Diagnostics; + +namespace Xtz.StronglyTyped.BuiltinTypes.Finance { /// /// Represents a currency. /// - public record Currency(CurrencyName Name, CurrencyCode Code, CurrencySymbol? Symbol); - + [DebuggerDisplay("{ToString(),nq}")] + public record Currency(CurrencyName Name, CurrencyCode Code, CurrencySymbol? Symbol) + { + public override string ToString() => $"{Name} ({Code}, symbol: {Symbol ?? ""})"; + } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/AvatarUri.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/AvatarUri.cs index 293af59..bdb7d49 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/AvatarUri.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/AvatarUri.cs @@ -3,7 +3,7 @@ namespace Xtz.StronglyTyped.BuiltinTypes.Internet { - // TODO: Use `AbsoluteUri` as inner type + // TODO: Vlad DX: Think about using `AbsoluteUri` as inner type (could be not the best idea to use strong type in strong type) /// /// Absolute avatar URL. /// diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/Email.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/Email.cs index 851aba4..03d8faf 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/Email.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/Email.cs @@ -11,14 +11,14 @@ namespace Xtz.StronglyTyped.BuiltinTypes.Internet [StrongType(typeof(MailAddress))] public partial class Email : IHasMailAddress { - public static readonly IReadOnlyCollection IllegalChars = new[] { ' ', '<', '>' }; + public static readonly IReadOnlyCollection ILLEGAL_CHARS = new[] { ' ', '<', '>' }; - internal static readonly string IllegalCharsString = $"'{string.Join("', '", IllegalChars)}"; + internal static readonly string ILLEGAL_CHARS_STRING = $"'{string.Join("', '", ILLEGAL_CHARS)}"; public Email(string value) : this(new MailAddress(value)) { - if (value.Any(c => IllegalChars.Contains(c))) Throw($"Characters {IllegalCharsString} are not allowed in email"); + if (value.Any(c => ILLEGAL_CHARS.Contains(c))) Throw($"Characters {ILLEGAL_CHARS_STRING} are not allowed in email"); } } } diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/ExampleEmail.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/ExampleEmail.cs index ff94dda..d2869f0 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/ExampleEmail.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/ExampleEmail.cs @@ -13,7 +13,7 @@ public partial class ExampleEmail : IHasMailAddress public ExampleEmail(string value) : base(new MailAddress(value)) { - if (value.Any(c => Email.IllegalChars.Contains(c))) Throw($"Characters {Email.IllegalCharsString} are not allowed in email"); + if (value.Any(c => Email.ILLEGAL_CHARS.Contains(c))) Throw($"Characters {Email.ILLEGAL_CHARS_STRING} are not allowed in email"); } } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/WebsiteProtocol.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/WebsiteProtocol.cs index f044998..149bda3 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Internet/WebsiteProtocol.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Internet/WebsiteProtocol.cs @@ -13,11 +13,13 @@ public partial class WebsiteProtocol /// /// HTTP protocol. /// + // ReSharper disable once UnusedMember.Global public static readonly WebsiteProtocol HTTP = new WebsiteProtocol("http"); /// /// HTTPS protocol. /// + // ReSharper disable once UnusedMember.Global public static readonly WebsiteProtocol HTTPS = new WebsiteProtocol("https"); protected override bool IsValid(string value) diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Name/FullName.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Name/FullName.cs index 9dbc163..0bbb309 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Name/FullName.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Name/FullName.cs @@ -1,7 +1,13 @@ -namespace Xtz.StronglyTyped.BuiltinTypes.Name +using System.Diagnostics; + +namespace Xtz.StronglyTyped.BuiltinTypes.Name { /// /// Full name. /// - public record FullName(FirstName FirstName, LastName LastName); + [DebuggerDisplay("{ToString(),nq}")] + public record FullName(FirstName FirstName, LastName LastName) + { + public override string ToString() => $"{FirstName} {LastName})"; + } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Strings/UpperCased.cs b/src/Xtz.StronglyTyped.BuiltinTypes/Strings/UpperCased.cs index 6b14f6d..49c0d85 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Strings/UpperCased.cs +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Strings/UpperCased.cs @@ -6,6 +6,7 @@ public class UpperCased : StronglyTyped { public UpperCased(string value) + // ReSharper disable once ConstantConditionalAccessQualifier #pragma warning disable 8604 : base(value?.ToUpperInvariant()) #pragma warning restore 8604 diff --git a/src/Xtz.StronglyTyped.BuiltinTypes/Xtz.StronglyTyped.BuiltinTypes.csproj b/src/Xtz.StronglyTyped.BuiltinTypes/Xtz.StronglyTyped.BuiltinTypes.csproj index ef14370..0628d6d 100644 --- a/src/Xtz.StronglyTyped.BuiltinTypes/Xtz.StronglyTyped.BuiltinTypes.csproj +++ b/src/Xtz.StronglyTyped.BuiltinTypes/Xtz.StronglyTyped.BuiltinTypes.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.BuiltinTypes - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,6 +33,11 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + True $(BaseIntermediateOutputPath)\GeneratedFiles @@ -43,10 +48,34 @@ Make compiler your friend, introduce semantics to your code. + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped.EntityFramework/ModelBuilderExtensions.cs b/src/Xtz.StronglyTyped.EntityFramework/ModelBuilderExtensions.cs index 5cba977..7fedbf8 100644 --- a/src/Xtz.StronglyTyped.EntityFramework/ModelBuilderExtensions.cs +++ b/src/Xtz.StronglyTyped.EntityFramework/ModelBuilderExtensions.cs @@ -56,6 +56,8 @@ public static void RegisterStronglyTypedConverters(this ModelBuilder modelBuilde .Entity(entityType.Name) .Property(propertyInfo.Name) .HasConversion(valueConverter); + + // ReSharper disable once RedundantJumpStatement continue; } diff --git a/src/Xtz.StronglyTyped.EntityFramework/Xtz.StronglyTyped.EntityFramework.csproj b/src/Xtz.StronglyTyped.EntityFramework/Xtz.StronglyTyped.EntityFramework.csproj index 1e706ab..76cfcbe 100644 --- a/src/Xtz.StronglyTyped.EntityFramework/Xtz.StronglyTyped.EntityFramework.csproj +++ b/src/Xtz.StronglyTyped.EntityFramework/Xtz.StronglyTyped.EntityFramework.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.EntityFramework - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,12 +33,41 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped.NewtonsoftJson/GlobalSuppressions.cs b/src/Xtz.StronglyTyped.NewtonsoftJson/GlobalSuppressions.cs new file mode 100644 index 0000000..897b1dd --- /dev/null +++ b/src/Xtz.StronglyTyped.NewtonsoftJson/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.NewtonsoftJson.NewtonsoftJsonConverterException")] diff --git a/src/Xtz.StronglyTyped.NewtonsoftJson/NewtonsoftJsonConverterException.cs b/src/Xtz.StronglyTyped.NewtonsoftJson/NewtonsoftJsonConverterException.cs new file mode 100644 index 0000000..f21d8e2 --- /dev/null +++ b/src/Xtz.StronglyTyped.NewtonsoftJson/NewtonsoftJsonConverterException.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; + +namespace Xtz.StronglyTyped.NewtonsoftJson +{ + [ExcludeFromCodeCoverage] + [Serializable] + public class NewtonsoftJsonConverterException : StronglyTypedException + { + public NewtonsoftJsonConverterException(Type type, string errorMessage) + : base(type, errorMessage) + { + } + + /// + /// Constructor is used for deserialization. + /// + protected NewtonsoftJsonConverterException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.NewtonsoftJson/StronglyTypedNewtonsoftConverter.cs b/src/Xtz.StronglyTyped.NewtonsoftJson/StronglyTypedNewtonsoftConverter.cs new file mode 100644 index 0000000..56b1606 --- /dev/null +++ b/src/Xtz.StronglyTyped.NewtonsoftJson/StronglyTypedNewtonsoftConverter.cs @@ -0,0 +1,280 @@ +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Xml; +using Newtonsoft.Json; +using Xtz.StronglyTyped.TypeConverters; + +namespace Xtz.StronglyTyped.NewtonsoftJson +{ + [SuppressMessage("Style", "IDE0034:Simplify 'default' expression", Justification = "Vlad DX: Reviewed (more readable code)")] + public class StronglyTypedNewtonsoftConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(IStronglyTyped).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var typeConverter = TypeDescriptor.GetConverter(objectType) as ICustomTypeConverter; + + switch (reader.Value) + { + case long longValue: + return ConvertFromLong(longValue, typeConverter!); + case double doubleValue: + return ConvertFromDouble(doubleValue, typeConverter!); + case BigInteger bigIntValue: + return ConvertFromBigInt(bigIntValue, typeConverter!); + } + + if (typeConverter!.InnerType == typeof(TimeSpan)) + { + return ConvertToTimeSpan(reader.Value!, typeConverter); + } + + return (IStronglyTyped)typeConverter.ConvertFrom(reader.Value!); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + return; + } + + var typeConverter = TypeDescriptor.GetConverter(value.GetType()) as ICustomTypeConverter; + if (typeConverter!.InnerType == typeof(bool)) + { + var boolValue = (value as IStronglyTyped)?.Value ?? default(bool); + writer.WriteValue(boolValue); + return; + } + + if (TryWriteNumber(value, typeConverter!.InnerType, writer)) + { + return; + } + + var stringValue = typeConverter.ConvertTo(value, typeof(string)) as string; + writer.WriteValue(stringValue); + } + + private static IStronglyTyped ConvertFromLong(long longValue, ICustomTypeConverter typeConverter) + { + if (typeConverter.InnerType == typeof(byte)) + { + var value = unchecked((byte)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(decimal)) + { + var value = (decimal)longValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(double)) + { + var value = (double)longValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(float)) + { + var value = (float)longValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(int)) + { + var value = unchecked((int)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(long)) + { + var result = (typeConverter as TypeConverter)!.ConvertFrom(longValue); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(sbyte)) + { + var value = unchecked((sbyte)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(short)) + { + var value = unchecked((short)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(uint)) + { + var value = unchecked((uint)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(ulong)) + { + var value = unchecked((ulong)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(ushort)) + { + var value = unchecked((ushort)longValue); + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + throw new NewtonsoftJsonConverterException(typeConverter.StrongType, $"Can't convert from '{typeof(long)}' to '{typeConverter.StrongType.FullName}'"); + } + + private static IStronglyTyped ConvertFromDouble(double doubleValue, ICustomTypeConverter typeConverter) + { + if (typeConverter.InnerType == typeof(double)) + { + var result = (typeConverter as TypeConverter)!.ConvertFrom(doubleValue); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(decimal)) + { + var value = (decimal)doubleValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(float)) + { + var value = (float)doubleValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + throw new NewtonsoftJsonConverterException(typeConverter.StrongType, $"Can't convert from '{typeof(double)}' to '{typeConverter.StrongType.FullName}'"); + } + + private static IStronglyTyped ConvertFromBigInt(BigInteger bigIntValue, ICustomTypeConverter typeConverter) + { + if (typeConverter.InnerType == typeof(decimal)) + { + var value = (decimal)bigIntValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + if (typeConverter.InnerType == typeof(ulong)) + { + var value = (ulong)bigIntValue; + var result = (typeConverter as TypeConverter)!.ConvertFrom(value); + return (IStronglyTyped)result!; + } + + throw new NewtonsoftJsonConverterException(typeConverter.StrongType, $"Can't convert from '{typeof(BigInteger)}' to '{typeConverter.StrongType.FullName}'"); + } + + private static IStronglyTyped ConvertToTimeSpan(object value, ICustomTypeConverter typeConverter) + { + var timeSpanValue = XmlConvert.ToTimeSpan(value.ToString()); + var result = typeConverter.ConvertFrom(timeSpanValue); + return (IStronglyTyped)result; + } + + private static bool TryWriteNumber(object value, Type innerType, JsonWriter writer) + { + if (innerType == typeof(decimal)) + { + var decimalValue = (value as IStronglyTyped)?.Value ?? default(decimal); + writer.WriteValue(decimalValue); + return true; + } + + if (innerType == typeof(double)) + { + var doubleValue = (value as IStronglyTyped)?.Value ?? default(double); + writer.WriteValue(doubleValue); + return true; + } + + if (innerType == typeof(float)) + { + var floatValue = (value as IStronglyTyped)?.Value ?? default(float); + writer.WriteValue(floatValue); + return true; + } + + if (innerType == typeof(int)) + { + var intValue = (value as IStronglyTyped)?.Value ?? default(int); + writer.WriteValue(intValue); + return true; + } + + if (innerType == typeof(long)) + { + var longValue = (value as IStronglyTyped)?.Value ?? default(long); + writer.WriteValue(longValue); + return true; + } + + if (innerType == typeof(uint)) + { + var uintValue = (value as IStronglyTyped)?.Value ?? default(uint); + writer.WriteValue(uintValue); + return true; + } + + if (innerType == typeof(ulong)) + { + var ulongValue = (value as IStronglyTyped)?.Value ?? default(ulong); + writer.WriteValue(ulongValue); + return true; + } + + if (innerType == typeof(byte)) + { + var byteValue = (value as IStronglyTyped)?.Value ?? default(byte); + writer.WriteValue(byteValue); + return true; + } + + if (innerType == typeof(sbyte)) + { + var sbyteValue = (value as IStronglyTyped)?.Value ?? default(sbyte); + writer.WriteValue(sbyteValue); + return true; + } + + if (innerType == typeof(short)) + { + var shortValue = (value as IStronglyTyped)?.Value ?? default(short); + writer.WriteValue(shortValue); + return true; + } + + if (innerType == typeof(ushort)) + { + var ushortValue = (value as IStronglyTyped)?.Value ?? default(ushort); + writer.WriteValue(ushortValue); + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj b/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj new file mode 100644 index 0000000..facb6af --- /dev/null +++ b/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj @@ -0,0 +1,82 @@ + + + + netstandard2.1 + 9 + enable + + + + Xtz.StronglyTyped.NewtonsoftJson + 0.23.0 + true + snupkg + Vlad DX + Extenza + 'Newtonsoft.Json' support for `Xtz.StronglyTyped`, library to strongly-type your interfaces (properties, methods, APIs, DB entities, appsettings). + +Eliminate stringly-typed interfaces. + +Make compiler your friend, introduce semantics to your code. + strongly-typed, strong type, type converter, Newtonsoft.Json, json serialization, appsettings, compiler + Copyright (c) Vlad DX, 2021 + git + https://github.com/dev-experience/Xtz.StronglyTyped + true + true + MIT + true + + + + true + true + + + + true + latest + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj.DotSettings b/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj.DotSettings new file mode 100644 index 0000000..30e1370 --- /dev/null +++ b/src/Xtz.StronglyTyped.NewtonsoftJson/Xtz.StronglyTyped.NewtonsoftJson.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.SourceGenerator/Attributes/Allow.cs b/src/Xtz.StronglyTyped.SourceGenerator/Attributes/Allow.cs index b6f9cf3..b705707 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/Attributes/Allow.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/Attributes/Allow.cs @@ -8,7 +8,7 @@ namespace Xtz.StronglyTyped.SourceGenerator [Flags] public enum Allow { - Unknown = 0, + None = 0, /// /// Allow empty strings or default struct values (but doesn't affect numbers). /// diff --git a/src/Xtz.StronglyTyped.SourceGenerator/Attributes/StrongTypeAttribute.cs b/src/Xtz.StronglyTyped.SourceGenerator/Attributes/StrongTypeAttribute.cs index 166f315..fe7910a 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/Attributes/StrongTypeAttribute.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/Attributes/StrongTypeAttribute.cs @@ -11,13 +11,13 @@ public class StrongTypeAttribute : Attribute public Allow Allow { get; } - public StrongTypeAttribute(Type innerType, Allow allow = Allow.Unknown) + public StrongTypeAttribute(Type innerType, Allow allow = Allow.None) { InnerType = innerType; Allow = allow; } - public StrongTypeAttribute(Allow allow = Allow.Unknown) + public StrongTypeAttribute(Allow allow = Allow.None) : this(typeof(string), allow) { } diff --git a/src/Xtz.StronglyTyped.SourceGenerator/CodeWriter.cs b/src/Xtz.StronglyTyped.SourceGenerator/CodeWriter.cs index 1ff429f..6c61d6b 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/CodeWriter.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/CodeWriter.cs @@ -33,13 +33,13 @@ public IDisposable BeginScope() { // TODO: Replace by pre-built array of spaces. Do substring Content.Append(new string(' ', IndentLevel * 4)).AppendLine("{"); - IndentLevel += 1; + IndentLevel++; return _scopeTracker; } public void EndScope() { - IndentLevel -= 1; + IndentLevel--; Content.Append(new string(' ', IndentLevel * 4)).AppendLine("}"); } @@ -49,10 +49,10 @@ public void EndScope() public override string ToString() => Content.ToString(); - public class ScopeTracker : IDisposable + public sealed class ScopeTracker : IDisposable { private readonly CodeWriter _parent; - + public ScopeTracker(CodeWriter parent) { _parent = parent; diff --git a/src/Xtz.StronglyTyped.SourceGenerator/DataExtractor.cs b/src/Xtz.StronglyTyped.SourceGenerator/DataExtractor.cs index b0a2329..424740b 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/DataExtractor.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/DataExtractor.cs @@ -133,12 +133,12 @@ public WorkItemKind ExtractItemKind(SyntaxNode syntaxNode) { if (string.IsNullOrEmpty(typeName)) return null; - if (KNOWN_TYPES.TryGetValue(typeName, out var knownType)) + if (KNOWN_TYPES.TryGetValue(typeName!, out var knownType)) { return knownType; } - var systemType = SYSTEM_PRIVATE_CORE_LIB_ASSEMBLY.GetType(typeName); + var systemType = SYSTEM_PRIVATE_CORE_LIB_ASSEMBLY.GetType(typeName!); if (systemType != null) { return systemType; @@ -223,9 +223,9 @@ private DoesAllowEmpty ExtractAllowEmpty(SemanticModel semanticModel, AttributeS // [StrongType(..., allow: Allow.Empty)] // ^ Constructor method var attributeSymbol = semanticModel.GetSymbolInfo(strongTypeAttributeSyntax); - var methodSymbol = attributeSymbol.Symbol as IMethodSymbol; + if (attributeSymbol.Symbol is not IMethodSymbol methodSymbol) return (DoesAllowEmpty)false; - var result = HasEnumArgument(semanticModel, methodSymbol!, attributeArgumentSyntaxes, Allow.Empty); + var result = HasEnumArgument(semanticModel, methodSymbol, attributeArgumentSyntaxes, Allow.Empty); return (DoesAllowEmpty)result; } @@ -287,7 +287,7 @@ private bool HasEnumArgument( // [StrongType(..., allow: Allow.Null)] // ^ - var hasParameterOfType = methodSymbol!.Parameters.Any(x => x.Type.ToDisplayString() == typeof(TEnum).FullName); + var hasParameterOfType = methodSymbol.Parameters.Any(x => x.Type.ToDisplayString() == typeof(TEnum).FullName); if (!hasParameterOfType) return false; // [StrongType(..., allow: Allow.Null)] @@ -305,7 +305,7 @@ private bool HasEnumArgument( // [StrongType(..., allow: Allow.Null | Allow.Empty)] // ^ var binaryOperation = semanticModel.GetOperation(binaryExpressionSyntax); - if (binaryOperation?.Type.ToDisplayString() == typeof(TEnum).FullName) + if (binaryOperation?.Type?.ToDisplayString() == typeof(TEnum).FullName) { // [StrongType(..., allow: Allow.Null | Allow.Empty)] // ^ @@ -360,9 +360,11 @@ private bool IsEnumValue( private static bool HasSingleParameter( SemanticModel semanticModel, - BaseMethodDeclarationSyntax methodDeclarationSyntax, + BaseMethodDeclarationSyntax? methodDeclarationSyntax, Type expectedType) { + if (methodDeclarationSyntax is null) return false; + // constructor(...) // ^ if (methodDeclarationSyntax.ParameterList.Parameters.Count != 1) return false; @@ -382,12 +384,11 @@ private static bool HasSingleParameter( } private static bool HasNameAndReturnType( - MethodDeclarationSyntax methodDeclarationSyntax, + MethodDeclarationSyntax? methodDeclarationSyntax, string expectedName, string expectedReturnType) { - var result = methodDeclarationSyntax.Identifier.Text == expectedName - && methodDeclarationSyntax.ReturnType.ToString() == expectedReturnType; + var result = methodDeclarationSyntax?.Identifier.Text == expectedName && methodDeclarationSyntax?.ReturnType.ToString() == expectedReturnType; return result; } } diff --git a/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/CodeWriterException.cs b/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/CodeWriterException.cs index 2f4c051..f681490 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/CodeWriterException.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/CodeWriterException.cs @@ -1,9 +1,11 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped.SourceGenerator { [ExcludeFromCodeCoverage] + [Serializable] public class CodeWriterException : ApplicationException { public CodeWriterException(string message) @@ -15,5 +17,13 @@ public CodeWriterException(string message, Exception innerException) : base(message, innerException) { } + + /// + /// Constructor is used for deserialization. + /// + protected CodeWriterException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/SyntaxReceiverException.cs b/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/SyntaxReceiverException.cs index 279de07..4c7162b 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/SyntaxReceiverException.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/Exceptions/SyntaxReceiverException.cs @@ -1,9 +1,11 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped.SourceGenerator { [ExcludeFromCodeCoverage] + [Serializable] public class SyntaxReceiverException : ApplicationException { public SyntaxReceiverException(string message) @@ -15,5 +17,13 @@ public SyntaxReceiverException(string message, Exception innerException) : base(message, innerException) { } + + /// + /// Constructor is used for deserialization. + /// + protected SyntaxReceiverException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.SourceGenerator/GlobalSuppressions.cs b/src/Xtz.StronglyTyped.SourceGenerator/GlobalSuppressions.cs new file mode 100644 index 0000000..a1e46ab --- /dev/null +++ b/src/Xtz.StronglyTyped.SourceGenerator/GlobalSuppressions.cs @@ -0,0 +1,14 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed. It's intended", Scope = "type", Target = "~T:Xtz.StronglyTyped.SourceGenerator.CodeWriterException")] +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed. It's intended", Scope = "type", Target = "~T:Xtz.StronglyTyped.SourceGenerator.SyntaxReceiverException")] +[assembly: SuppressMessage("Major Code Smell", "S108:Nested blocks of code should not be left empty", Justification = "Vlad DX: Reviewed. Source generator", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.StronglyTypedGenerator.WriteClass(Xtz.StronglyTyped.SourceGenerator.CodeWriter,Xtz.StronglyTyped.SourceGenerator.StronglyTypedWorkItem)")] +[assembly: SuppressMessage("Major Code Smell", "S108:Nested blocks of code should not be left empty", Justification = "Vlad DX: Reviewed. Source generator", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.StronglyTypedGenerator.WriteGuidStringConstructor(Xtz.StronglyTyped.SourceGenerator.CodeWriter,Xtz.StronglyTyped.SourceGenerator.StronglyTypedWorkItem)")] +[assembly: SuppressMessage("Major Code Smell", "S108:Nested blocks of code should not be left empty", Justification = "Vlad DX: Reviewed. Source generator", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.StronglyTypedGenerator.WriteStringConstructor(Xtz.StronglyTyped.SourceGenerator.CodeWriter,Xtz.StronglyTyped.SourceGenerator.StronglyTypedWorkItem)")] +[assembly: SuppressMessage("Major Code Smell", "S108:Nested blocks of code should not be left empty", Justification = "Vlad DX: Reviewed. Source generator", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.StronglyTypedGenerator.TryWriteParsingStringConstructor(Xtz.StronglyTyped.SourceGenerator.CodeWriter,Xtz.StronglyTyped.SourceGenerator.StronglyTypedWorkItem)")] +[assembly: SuppressMessage("Minor Code Smell", "S3626:Jump statements should not be redundant", Justification = "Vlad DX: Reviewed", Scope = "member", Target = "~M:Xtz.StronglyTyped.SourceGenerator.StronglyTypedGenerator.TryWriteToString(Xtz.StronglyTyped.SourceGenerator.CodeWriter,Xtz.StronglyTyped.SourceGenerator.StronglyTypedWorkItem)")] diff --git a/src/Xtz.StronglyTyped.SourceGenerator/StrongTypes/ConstructorDescriptor.cs b/src/Xtz.StronglyTyped.SourceGenerator/StrongTypes/ConstructorDescriptor.cs index 0ac29e3..1eb7e79 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/StrongTypes/ConstructorDescriptor.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/StrongTypes/ConstructorDescriptor.cs @@ -1,4 +1,7 @@ -namespace Xtz.StronglyTyped.SourceGenerator +using System.Diagnostics.CodeAnalysis; + +namespace Xtz.StronglyTyped.SourceGenerator { + [ExcludeFromCodeCoverage] public record ConstructorDescriptor(string TypeName, string ParsingExpression); } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped.SourceGenerator/StronglyTypedGenerator.cs b/src/Xtz.StronglyTyped.SourceGenerator/StronglyTypedGenerator.cs index 7839218..e52c362 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/StronglyTypedGenerator.cs +++ b/src/Xtz.StronglyTyped.SourceGenerator/StronglyTypedGenerator.cs @@ -28,15 +28,15 @@ public class StronglyTypedGenerator : IStronglyTypedGenerator { typeof(uint), new("uint", "uint.Parse(value)") }, { typeof(ulong), new("ulong", "ulong.Parse(value)") }, { typeof(ushort), new("ushort", "ushort.Parse(value)") }, - { typeof(DateTime), new(typeof(DateTime).FullName, "System.DateTime.Parse(value)") }, - { typeof(TimeSpan), new(typeof(TimeSpan).FullName, "System.TimeSpan.Parse(value)") }, - { typeof(Guid), new(typeof(Guid).FullName, "System.Guid.Parse(value)") }, + { typeof(DateTime), new(typeof(DateTime).FullName, "DateTime.Parse(value)") }, + { typeof(TimeSpan), new(typeof(TimeSpan).FullName, "TimeSpan.Parse(value)") }, + { typeof(Guid), new(typeof(Guid).FullName, "Guid.Parse(value)") }, // Skipping `MailAddress` as it has `(string value)` constructor { typeof(IPAddress), new(typeof(IPAddress).FullName, "System.Net.IPAddress.Parse(value)") }, { typeof(PhysicalAddress), new(typeof(PhysicalAddress).FullName, "System.Net.NetworkInformation.PhysicalAddress.Parse(value)") }, // Skipping `Uri` as it has `(string value)` constructor }; - + private readonly IDataExtractor _dataExtractor = new DataExtractor(); private readonly List _log = new(); @@ -89,7 +89,7 @@ public void Execute(GeneratorExecutionContext context) #endif // IMPORTANT: Check if you use any types from `Xtz.StronglyTyped` library or any other library. Remove if any. Dependencies are not copied along with source generator (if they are not analyzers as well). // https://github.com/dotnet/roslyn/discussions/47517#discussioncomment-63842 - + _log.Add("\nIMPORTANT: Check if you use any types from `Xtz.StronglyTyped` library or any other library. Remove if any. Dependencies are not copied along with source generator (if they are not analyzers as well).\nhttps://github.com/dotnet/roslyn/discussions/47517#discussioncomment-63842\n"); _log.Add($"Method '{nameof(StronglyTypedGenerator)}.{nameof(Execute)}()' threw an exception '{e.Message}'.\n\nStack trace: {e.StackTrace}\n\nProcess ID: {processId}\n\nProcess name: {processName}\n\nFusion log: {e.FusionLog}"); } @@ -115,7 +115,7 @@ public void Execute(GeneratorExecutionContext context) { context.AddSource("_1-receiver-log", BuildLogText(receiver.Log, "SYNTAX RECEIVER LOG")); context.AddSource("_2-data-extractor-log", BuildLogText(_dataExtractor.Log, "DATA EXTRACTOR LOG")); - context.AddSource($"_3-generator-log", BuildLogText(_log, "GENERATOR LOG")); + context.AddSource("_3-generator-log", BuildLogText(_log, "GENERATOR LOG")); } } @@ -123,17 +123,29 @@ private string GenerateSourceCode(StronglyTypedWorkItem workItem, DateTime times { var writer = new CodeWriter(); - WriteBanner(writer, workItem, timestamp); + var version = GetType().Assembly.GetName().Version; + var assemblyVersion = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; + + WriteBanner(writer, workItem, assemblyVersion, timestamp); + writer.AppendLine("//// ReSharper disable All"); + writer.AppendLine("#pragma warning disable"); + writer.AppendLine("#nullable enable"); + writer.AppendLine("#nullable disable warnings"); writer.AppendLine(); + using (writer.BeginScope($"namespace {workItem.Namespace}")) { + writer.AppendLine("using System;"); writer.AppendLine("using System.ComponentModel;"); writer.AppendLine("using System.Text.Json.Serialization;"); + writer.AppendLine("using Xtz.StronglyTyped;"); + writer.AppendLine("using Xtz.StronglyTyped.TypeConverters;"); writer.AppendLine(); + writer.AppendLine($"[System.CodeDom.Compiler.GeneratedCode(\"{GetType().FullName}\", \"{assemblyVersion}\")]"); WriteTypeConverter(writer, workItem); - writer.AppendLine($"[JsonConverter(typeof(Xtz.StronglyTyped.TypeConverters.StronglyTypedJsonConverter<{workItem.Namespace}.{workItem.TypeName}>))]"); + writer.AppendLine($"[JsonConverter(typeof(StronglyTypedJsonConverter<{workItem.TypeName}>))]"); switch (workItem.Kind) { @@ -143,6 +155,7 @@ private string GenerateSourceCode(StronglyTypedWorkItem workItem, DateTime times case WorkItemKind.Struct: WriteStruct(writer, workItem); break; + // ReSharper disable once RedundantCaseLabel case WorkItemKind.Unknown: default: throw new CodeWriterException($"Not supported work item type '{workItem.Kind}'"); @@ -153,30 +166,28 @@ private string GenerateSourceCode(StronglyTypedWorkItem workItem, DateTime times return generatedSourceCode; } - private void WriteBanner(CodeWriter writer, StronglyTypedWorkItem workItem, DateTime timestamp) + private void WriteBanner(CodeWriter writer, StronglyTypedWorkItem workItem, string assemblyVersion, DateTime timestamp) { - var version = GetType().Assembly.GetName().Version; - var assemblyVersion = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; - writer.AppendLine( - $@"//------------------------------------ -// -// Type `{workItem.Namespace}.{workItem.TypeName}` -// -// This code was generated by generator '{GetType().FullName}' -// Assembly Version: {assemblyVersion} -// Generation timestamp: {timestamp:s}Z -// -//------------------------------------"); + $@"/* + + Type `{workItem.Namespace}.{workItem.TypeName}` + + This code was generated by generator '{GetType().FullName}' + Assembly Version: {assemblyVersion} + Generation timestamp: {timestamp:s}Z + +*/"); + writer.AppendLine(); } - private void WriteTypeConverter(CodeWriter writer, StronglyTypedWorkItem workItem) + private static void WriteTypeConverter(CodeWriter writer, StronglyTypedWorkItem workItem) { var valueType = workItem.InnerType; var typeConverter = valueType switch { - var t when t == typeof(string) => $"[TypeConverter(typeof(Xtz.StronglyTyped.TypeConverters.StringTypeConverter<{workItem.TypeName}>))]", - _ => $"[TypeConverter(typeof(Xtz.StronglyTyped.TypeConverters.TypeConverter<{workItem.TypeName}, {workItem.InnerType.FullName}>))]", + var t when t == typeof(string) => $"[TypeConverter(typeof(StringTypeConverter<{workItem.TypeName}>))]", + _ => $"[TypeConverter(typeof(TypeConverter<{workItem.TypeName}, {workItem.InnerType.FullName}>))]", }; writer.AppendLine(typeConverter); @@ -185,14 +196,14 @@ private void WriteTypeConverter(CodeWriter writer, StronglyTypedWorkItem workIte private void WriteClass(CodeWriter writer, StronglyTypedWorkItem workItem) { var baseType = !workItem.ExtraFeatures.HasBaseClass - ? $" Xtz.StronglyTyped.StronglyTyped<{workItem.InnerType.FullName}>," + ? $" StronglyTyped<{workItem.InnerType.FullName}>," : String.Empty; var sealedStr = workItem.ExtraFeatures.IsAbstract ? string.Empty : " sealed"; - using (writer.BeginScope($"public{sealedStr} partial class {workItem.TypeName} :{baseType} System.IEquatable<{workItem.TypeName}>")) + using (writer.BeginScope($"public{sealedStr} partial class {workItem.TypeName} :{baseType} IEquatable<{workItem.TypeName}>")) { WriteXmlSummary(writer, $"Initializes a new instance of the class."); WriteXmlParam(writer, "value", "Inner value"); @@ -209,7 +220,7 @@ private void WriteClass(CodeWriter writer, StronglyTypedWorkItem workItem) TryWriteToString(writer, workItem); - WriteEquatableEquals(writer, workItem); + WriteClassEquatableEquals(writer, workItem); writer.AppendLine(); WriteExplicitOperatorToStrongType(writer, workItem); @@ -232,13 +243,13 @@ private void TryWriteAllowEmpty(CodeWriter writer, StronglyTypedWorkItem workIte private void WriteStruct(CodeWriter writer, StronglyTypedWorkItem workItem) { writer.AppendLine("[System.Diagnostics.DebuggerDisplay(\"[struct {GetType().Name,nq}] {Value}\")]"); - using (writer.BeginScope($"public readonly partial struct {workItem.TypeName} : Xtz.StronglyTyped.IStronglyTyped<{workItem.InnerType.FullName}>, System.IEquatable<{workItem.TypeName}>")) + using (writer.BeginScope($"public readonly partial struct {workItem.TypeName} : IStronglyTyped<{workItem.InnerType.FullName}>, IEquatable<{workItem.TypeName}>")) { WriteXmlSummary(writer, "Default instance."); writer.AppendLine($"public static readonly {workItem.TypeName} Default;"); writer.AppendLine(); - WriteXmlSummary(writer, $"Inner value."); + WriteXmlSummary(writer, "Inner value."); writer.AppendLine($"public {workItem.InnerType.FullName} Value {{ get; }}"); writer.AppendLine(); @@ -258,7 +269,7 @@ private void WriteStruct(CodeWriter writer, StronglyTypedWorkItem workItem) TryWriteToString(writer, workItem); - WriteEquatableEquals(writer, workItem); + WriteStructEquatableEquals(writer, workItem); writer.AppendLine(); WriteStructEqualityMethods(writer, workItem); @@ -299,7 +310,7 @@ private void WriteGuidStringConstructor(CodeWriter writer, StronglyTypedWorkItem WriteXmlSummary(writer, $"Initializes a new instance of the {typeKindStr}."); writer.AppendLine($"public {workItem.TypeName}()"); - writer.AppendLine(" : this(System.Guid.NewGuid())"); + writer.AppendLine(" : this(Guid.NewGuid())"); using (writer.BeginScope()) { @@ -348,7 +359,7 @@ private void WriteStructThrowIfInvalid(CodeWriter writer, StronglyTypedWorkItem } } - if (workItem.InnerType == typeof (string)) + if (workItem.InnerType == typeof(string) && !workItem.ExtraFeatures.DoesAllowEmpty) { writer.AppendLine(); using (writer.BeginScope("if (value == string.Empty)")) @@ -368,7 +379,7 @@ private void WriteStructThrowIfInvalid(CodeWriter writer, StronglyTypedWorkItem } writer.AppendLine(); - writer.AppendLine("private void Throw(string errorMessage) => throw new Xtz.StronglyTyped.StronglyTypedException(GetType(), errorMessage);"); + writer.AppendLine("private void Throw(string errorMessage) => throw new StronglyTypedException(GetType(), errorMessage);"); writer.AppendLine(); } @@ -387,6 +398,7 @@ private void WriteStructEqualityMethods(CodeWriter writer, StronglyTypedWorkItem WriteXmlReturns(writer, "A 32-bit signed integer that is the hash code for this instance."); using (writer.BeginScope("public override int GetHashCode()")) { + // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (workItem.InnerType.IsValueType) { writer.AppendLine("return Value.GetHashCode();"); @@ -398,12 +410,12 @@ private void WriteStructEqualityMethods(CodeWriter writer, StronglyTypedWorkItem } } - private static void WriteEquatableEquals(CodeWriter writer, StronglyTypedWorkItem workItem) + private static void WriteClassEquatableEquals(CodeWriter writer, StronglyTypedWorkItem workItem) { WriteXmlSummary(writer, "Determines whether the specified object is equal to the current instance."); WriteXmlParam(writer, "other", "The object to compare with the current instance."); WriteXmlReturns(writer, " if the specified object is equal to the current instance; otherwise, ."); - using (writer.BeginScope($"public bool Equals({workItem.TypeName} other)")) + using (writer.BeginScope($"public bool Equals({workItem.TypeName}? other)")) { writer.AppendLine("if (ReferenceEquals(null, other)) return false;"); writer.AppendLine("if (ReferenceEquals(this, other)) return true;"); @@ -411,37 +423,72 @@ private static void WriteEquatableEquals(CodeWriter writer, StronglyTypedWorkIte } } + private static void WriteStructEquatableEquals(CodeWriter writer, StronglyTypedWorkItem workItem) + { + WriteXmlSummary(writer, "Determines whether the specified object is equal to the current instance."); + WriteXmlParam(writer, "other", "The object to compare with the current instance."); + WriteXmlReturns(writer, " if the specified object is equal to the current instance; otherwise, ."); + using (writer.BeginScope($"public bool Equals({workItem.TypeName} other)")) + { + writer.AppendLine("return Equals(Value, other.Value);"); + } + } + private static void TryWriteToString(CodeWriter writer, StronglyTypedWorkItem workItem) { - if (workItem.Kind == WorkItemKind.Struct && !workItem.ExtraFeatures.HasToString) + if (!workItem.ExtraFeatures.HasToString) { - WriteXmlSummary(writer, "Returns a string that represents inner value."); - WriteXmlReturns(writer, "A string that represents inner value."); - using (writer.BeginScope("public override string ToString()")) + // Order of ifs is important + + if (workItem.InnerType == typeof(Guid)) { - if (workItem.InnerType == typeof(Guid)) + WriteXmlSummary(writer, "Returns a string that represents inner ."); + WriteXmlReturns(writer, "A string that represents inner ."); + using (writer.BeginScope("public override string ToString()")) { writer.AppendLine("return $\"{Value:D}\";"); } - else + writer.AppendLine(); + return; + } + + if (workItem.InnerType == typeof(DateTime)) + { + WriteXmlSummary(writer, "Returns an ISO-8601 string that represents inner ."); + WriteXmlReturns(writer, "An ISO-8601 string that represents inner ."); + using (writer.BeginScope("public override string ToString()")) { - writer.AppendLine("return $\"{Value}\";"); + writer.AppendLine("return $\"{Value.ToUniversalTime():s}Z\";"); } + writer.AppendLine(); + return; } - writer.AppendLine(); - return; - } - if (workItem.Kind == WorkItemKind.Class && !workItem.ExtraFeatures.HasToString && workItem.InnerType == typeof(Guid)) - { - WriteXmlSummary(writer, "Returns a string that represents inner ."); - WriteXmlReturns(writer, "A string that represents inner ."); - using (writer.BeginScope("public override string ToString()")) + if (workItem.InnerType == typeof(TimeSpan)) + { + WriteXmlSummary(writer, "Returns an ISO-8601 string that represents inner ."); + WriteXmlReturns(writer, "An ISO-8601 string that represents inner ."); + using (writer.BeginScope("public override string ToString()")) + { + writer.AppendLine("return $\"{System.Xml.XmlConvert.ToString(Value)}\";"); + } + writer.AppendLine(); + return; + } + + if (workItem.Kind == WorkItemKind.Struct) { - writer.AppendLine("return $\"{Value:D}\";"); + WriteXmlSummary(writer, "Returns a string that represents inner value."); + WriteXmlReturns(writer, "A string that represents inner value."); + using (writer.BeginScope("public override string ToString()")) + { + writer.AppendLine("return $\"{Value}\";"); + } + writer.AppendLine(); + + // ReSharper disable once RedundantJumpStatement + return; } - writer.AppendLine(); - return; } } @@ -534,9 +581,9 @@ private static SourceText BuildLogText(IReadOnlyCollection log, string t { var version = typeof(StronglyTypedGenerator).Assembly.GetName().Version; var assemblyVersion = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; - + var result = SourceText.From( - string.Format(@"/*{0}{1}{0}{0}{2}{0}{0}{3}{0}{0}{4}{0}{0}*/", + string.Format("/*{0}{1}{0}{0}{2}{0}{0}{3}{0}{0}{4}{0}{0}*/", Environment.NewLine, title, $"This code was generated by generator '{typeof(StronglyTypedGenerator).FullName}'\nAssembly Version: {assemblyVersion}", diff --git a/src/Xtz.StronglyTyped.SourceGenerator/Xtz.StronglyTyped.SourceGenerator.csproj b/src/Xtz.StronglyTyped.SourceGenerator/Xtz.StronglyTyped.SourceGenerator.csproj index aebdbe7..8dfb617 100644 --- a/src/Xtz.StronglyTyped.SourceGenerator/Xtz.StronglyTyped.SourceGenerator.csproj +++ b/src/Xtz.StronglyTyped.SourceGenerator/Xtz.StronglyTyped.SourceGenerator.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.SourceGenerator - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -29,6 +29,11 @@ true + + true + latest + + false @@ -45,15 +50,43 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped.Swashbuckle/StronglyTypedSchemaFilter.cs b/src/Xtz.StronglyTyped.Swashbuckle/StronglyTypedSchemaFilter.cs index 4789bb0..bebbb3e 100644 --- a/src/Xtz.StronglyTyped.Swashbuckle/StronglyTypedSchemaFilter.cs +++ b/src/Xtz.StronglyTyped.Swashbuckle/StronglyTypedSchemaFilter.cs @@ -16,7 +16,7 @@ namespace Xtz.StronglyTyped.Swashbuckle public class StronglyTypedSchemaFilter : ISchemaFilter { // TODO: Replace strings by strong types - private readonly Dictionary TYPE_MAPPING = new() + private static readonly Dictionary TYPE_MAPPING = new() { { typeof(string), ("string", "string") }, { typeof(bool), ("boolean", null) }, diff --git a/src/Xtz.StronglyTyped.Swashbuckle/Xtz.StronglyTyped.Swashbuckle.csproj b/src/Xtz.StronglyTyped.Swashbuckle/Xtz.StronglyTyped.Swashbuckle.csproj index 72e38fe..524dc0a 100644 --- a/src/Xtz.StronglyTyped.Swashbuckle/Xtz.StronglyTyped.Swashbuckle.csproj +++ b/src/Xtz.StronglyTyped.Swashbuckle/Xtz.StronglyTyped.Swashbuckle.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped.Swashbuckle - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,12 +33,41 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/Xtz.StronglyTyped.sln b/src/Xtz.StronglyTyped.sln index 54e54a6..085f7fa 100644 --- a/src/Xtz.StronglyTyped.sln +++ b/src/Xtz.StronglyTyped.sln @@ -35,7 +35,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.SourceGen EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.EntityFramework.IntegrationTests", "Tests\Xtz.StronglyTyped.EntityFramework.IntegrationTests\Xtz.StronglyTyped.EntityFramework.IntegrationTests.csproj", "{857370EC-A6FA-47FE-9005-8CC4D752630F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.Api_3_1.IntegrationTests", "Xtz.StronglyTyped.Api_3_1.IntegrationTests\Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj", "{1AAE34E7-203E-41D3-A054-4767C5A99FAC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.NewtonsoftJson", "Xtz.StronglyTyped.NewtonsoftJson\Xtz.StronglyTyped.NewtonsoftJson.csproj", "{D7EB61AD-95C7-418C-B1B5-60D0B73905EA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.NewtonsoftJson.UnitTests", "Tests\Xtz.StronglyTyped.NewtonsoftJson.UnitTests\Xtz.StronglyTyped.NewtonsoftJson.UnitTests.csproj", "{97EDCF82-8DA3-4DB1-96C4-FB2481A75666}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{C6D98E0C-09A4-4152-914D-411DB65B1379}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xtz.StronglyTyped.Api_3_1.IntegrationTests", "Tests\Xtz.StronglyTyped.Api_3_1.IntegrationTests\Xtz.StronglyTyped.Api_3_1.IntegrationTests.csproj", "{975017C6-0E2B-4F10-BE65-B412755BEDF7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -99,10 +108,18 @@ Global {857370EC-A6FA-47FE-9005-8CC4D752630F}.Debug|Any CPU.Build.0 = Debug|Any CPU {857370EC-A6FA-47FE-9005-8CC4D752630F}.Release|Any CPU.ActiveCfg = Release|Any CPU {857370EC-A6FA-47FE-9005-8CC4D752630F}.Release|Any CPU.Build.0 = Release|Any CPU - {1AAE34E7-203E-41D3-A054-4767C5A99FAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1AAE34E7-203E-41D3-A054-4767C5A99FAC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1AAE34E7-203E-41D3-A054-4767C5A99FAC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1AAE34E7-203E-41D3-A054-4767C5A99FAC}.Release|Any CPU.Build.0 = Release|Any CPU + {D7EB61AD-95C7-418C-B1B5-60D0B73905EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7EB61AD-95C7-418C-B1B5-60D0B73905EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7EB61AD-95C7-418C-B1B5-60D0B73905EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7EB61AD-95C7-418C-B1B5-60D0B73905EA}.Release|Any CPU.Build.0 = Release|Any CPU + {97EDCF82-8DA3-4DB1-96C4-FB2481A75666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97EDCF82-8DA3-4DB1-96C4-FB2481A75666}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97EDCF82-8DA3-4DB1-96C4-FB2481A75666}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97EDCF82-8DA3-4DB1-96C4-FB2481A75666}.Release|Any CPU.Build.0 = Release|Any CPU + {975017C6-0E2B-4F10-BE65-B412755BEDF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {975017C6-0E2B-4F10-BE65-B412755BEDF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {975017C6-0E2B-4F10-BE65-B412755BEDF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {975017C6-0E2B-4F10-BE65-B412755BEDF7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -115,7 +132,8 @@ Global {0002B673-EEEC-42DE-BBD7-B434C01E4F3E} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} {F5E5B3F6-F0D7-4B11-A99C-87E3ADCEEFFE} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} {857370EC-A6FA-47FE-9005-8CC4D752630F} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} - {1AAE34E7-203E-41D3-A054-4767C5A99FAC} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} + {97EDCF82-8DA3-4DB1-96C4-FB2481A75666} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} + {975017C6-0E2B-4F10-BE65-B412755BEDF7} = {364CF428-8597-468D-9B5E-8D9A7BC6CC29} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F4FB6146-7992-4E75-B5F9-22B2ADA3C82F} diff --git a/src/Xtz.StronglyTyped.sln.DotSettings b/src/Xtz.StronglyTyped.sln.DotSettings new file mode 100644 index 0000000..cf9e2c7 --- /dev/null +++ b/src/Xtz.StronglyTyped.sln.DotSettings @@ -0,0 +1,5 @@ + + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + True \ No newline at end of file diff --git a/src/Xtz.StronglyTyped/GlobalSuppressions.cs b/src/Xtz.StronglyTyped/GlobalSuppressions.cs new file mode 100644 index 0000000..735b43c --- /dev/null +++ b/src/Xtz.StronglyTyped/GlobalSuppressions.cs @@ -0,0 +1,15 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.InvalidValueException")] +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.StronglyTypedException")] +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.TypeConverters.JsonConverterException")] +[assembly: SuppressMessage("Design", "RCS1194:Implement exception constructors.", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.TypeConverters.StringTypeConverterException")] +[assembly: SuppressMessage("Blocker Code Smell", "S3875:\"operator==\" should not be overloaded on reference types", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.StronglyTyped`1")] +[assembly: SuppressMessage("Style", "IDE0002:Name can be simplified", Justification = "Vlad DX: Reviewed", Scope = "type", Target = "~T:Xtz.StronglyTyped.StronglyTyped`1")] +[assembly: SuppressMessage("Style", "IDE0034:Simplify 'default' expression", Justification = "Vlad DX: Reviewed. More readable", Scope = "type", Target = "~T:Xtz.StronglyTyped.TypeConverters.StronglyTypedJsonConverter`1")] +[assembly: SuppressMessage("Major Code Smell", "S1066:Collapsible \"if\" statements should be merged", Justification = "Vlad DX: Reviewed. More readable", Scope = "member", Target = "~M:Xtz.StronglyTyped.StronglyTyped`1.ThrowIfInvalid(`0)")] diff --git a/src/Xtz.StronglyTyped/IStronglyTyped.cs b/src/Xtz.StronglyTyped/IStronglyTyped.cs index bd1c452..777ce87 100644 --- a/src/Xtz.StronglyTyped/IStronglyTyped.cs +++ b/src/Xtz.StronglyTyped/IStronglyTyped.cs @@ -1,7 +1,7 @@ -using System; - -namespace Xtz.StronglyTyped +namespace Xtz.StronglyTyped { + // TODO: Check out `Microsoft.CodeAnalysis.PublicApiAnalyzers` analyzer + /// /// Base interface for strongly-typed classes. /// diff --git a/src/Xtz.StronglyTyped/InvalidValueException.cs b/src/Xtz.StronglyTyped/InvalidValueException.cs index d9dd5fb..1a31d8c 100644 --- a/src/Xtz.StronglyTyped/InvalidValueException.cs +++ b/src/Xtz.StronglyTyped/InvalidValueException.cs @@ -1,12 +1,23 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped { [ExcludeFromCodeCoverage] + [Serializable] public class InvalidValueException : StronglyTypedException { - public InvalidValueException(Type type, string errorMessage) : base(type, errorMessage) + public InvalidValueException(Type type, string errorMessage) + : base(type, errorMessage) + { + } + + /// + /// Constructor is used for deserialization. + /// + protected InvalidValueException(SerializationInfo info, StreamingContext context) + : base(info, context) { } } diff --git a/src/Xtz.StronglyTyped/StronglyTyped.Operators.cs b/src/Xtz.StronglyTyped/StronglyTyped.Operators.cs index 31ca97c..39a8fda 100644 --- a/src/Xtz.StronglyTyped/StronglyTyped.Operators.cs +++ b/src/Xtz.StronglyTyped/StronglyTyped.Operators.cs @@ -1,37 +1,38 @@ -using System; +using System.Diagnostics.CodeAnalysis; namespace Xtz.StronglyTyped { + [SuppressMessage("ReSharper", "RedundantNameQualifier")] public abstract partial class StronglyTyped { public static bool operator ==(StronglyTyped objA, StronglyTyped objB) { - return Object.Equals(objA, objB); + return object.Equals(objA, objB); } public static bool operator !=(StronglyTyped objA, StronglyTyped objB) { - return !Object.Equals(objA, objB); + return !object.Equals(objA, objB); } public static bool operator ==(object objA, StronglyTyped objB) { - return Object.Equals(objA, objB); + return object.Equals(objA, objB); } public static bool operator !=(object objA, StronglyTyped objB) { - return !Object.Equals(objA, objB); + return !object.Equals(objA, objB); } public static bool operator ==(StronglyTyped objA, object objB) { - return Object.Equals(objA, objB); + return object.Equals(objA, objB); } public static bool operator !=(StronglyTyped objA, object objB) { - return !Object.Equals(objA, objB); + return !object.Equals(objA, objB); } public static implicit operator TInnerType?(StronglyTyped? value) diff --git a/src/Xtz.StronglyTyped/StronglyTyped.cs b/src/Xtz.StronglyTyped/StronglyTyped.cs index 669106e..6dbf181 100644 --- a/src/Xtz.StronglyTyped/StronglyTyped.cs +++ b/src/Xtz.StronglyTyped/StronglyTyped.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; namespace Xtz.StronglyTyped { @@ -29,8 +28,9 @@ private void ThrowIfInvalid(TInnerType value) Throw($" value is invalid for type {GetType()}"); } - if (ShouldThrowIfEmpty() && !typeof(TInnerType).IsPrimitive) + if (ShouldThrowIfEmpty() && !(typeof(TInnerType).IsPrimitive || typeof(TInnerType) == typeof(decimal))) { + // ReSharper disable once RedundantNameQualifier if (Equals(value, string.Empty) || object.Equals(value, default(TInnerType))) { Throw($"'{value}' value is invalid for type {GetType()}"); @@ -44,6 +44,7 @@ private void ThrowIfInvalid(TInnerType value) } // Bypass. Can be overriden + // ReSharper disable once VirtualMemberNeverOverridden.Global protected virtual bool ShouldThrowIfEmpty() => true; protected void Throw(string errorMessage) => throw new InvalidValueException(GetType(), errorMessage); @@ -53,6 +54,7 @@ private void ThrowIfInvalid(TInnerType value) public override bool Equals(object? obj) { + // ReSharper disable once RedundantNameQualifier if (object.ReferenceEquals(this, obj)) { return true; @@ -78,11 +80,13 @@ public override bool Equals(object? obj) public override int GetHashCode() { + // ReSharper disable once ConstantConditionalAccessQualifier return Value?.GetHashCode() ?? default; } public override string ToString() { + // ReSharper disable once ConstantConditionalAccessQualifier return Value?.ToString() ?? string.Empty; } diff --git a/src/Xtz.StronglyTyped/StronglyTypedException.cs b/src/Xtz.StronglyTyped/StronglyTypedException.cs index f215ca7..63b6c6f 100644 --- a/src/Xtz.StronglyTyped/StronglyTypedException.cs +++ b/src/Xtz.StronglyTyped/StronglyTypedException.cs @@ -1,9 +1,12 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; +using System.Security.Permissions; namespace Xtz.StronglyTyped { [ExcludeFromCodeCoverage] + [Serializable] public class StronglyTypedException : Exception { public Type Type { get; } @@ -19,5 +22,21 @@ public StronglyTypedException(Type type, string errorMessage, Exception innerExc { Type = type; } + + /// + /// Constructor is used for deserialization. + /// + protected StronglyTypedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + Type = (Type)info.GetValue(nameof(Type), typeof(Type)); + } + + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue(nameof(Type), Type); + } } } diff --git a/src/Xtz.StronglyTyped/TypeConverters/ICustomTypeConverter.cs b/src/Xtz.StronglyTyped/TypeConverters/ICustomTypeConverter.cs index c086f4c..73c843e 100644 --- a/src/Xtz.StronglyTyped/TypeConverters/ICustomTypeConverter.cs +++ b/src/Xtz.StronglyTyped/TypeConverters/ICustomTypeConverter.cs @@ -7,5 +7,15 @@ public interface ICustomTypeConverter Type StrongType { get; } Type InnerType { get; } + + /// + /// Converts the given value to the converter's native type. + /// + object ConvertFrom(object value); + + /// + /// Converts the given value object to the specified destination type using the arguments. + /// + object ConvertTo(object value, Type destinationType); } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped/TypeConverters/NewtonsoftJsonConverterException.cs b/src/Xtz.StronglyTyped/TypeConverters/NewtonsoftJsonConverterException.cs new file mode 100644 index 0000000..0966283 --- /dev/null +++ b/src/Xtz.StronglyTyped/TypeConverters/NewtonsoftJsonConverterException.cs @@ -0,0 +1,24 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; + +namespace Xtz.StronglyTyped.TypeConverters +{ + [ExcludeFromCodeCoverage] + [Serializable] + public class JsonConverterException : StronglyTypedException + { + public JsonConverterException(Type type, string errorMessage) + : base(type, errorMessage) + { + } + + /// + /// Constructor is used for deserialization. + /// + protected JsonConverterException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/Xtz.StronglyTyped/TypeConverters/StringTypeConverterException.cs b/src/Xtz.StronglyTyped/TypeConverters/StringTypeConverterException.cs index 2a771ca..e619f78 100644 --- a/src/Xtz.StronglyTyped/TypeConverters/StringTypeConverterException.cs +++ b/src/Xtz.StronglyTyped/TypeConverters/StringTypeConverterException.cs @@ -1,13 +1,23 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped.TypeConverters { [ExcludeFromCodeCoverage] + [Serializable] public class StringTypeConverterException : StronglyTypedException { public StringTypeConverterException(Type type, string errorMessage) : base(type, errorMessage) { } + + /// + /// Constructor is used for deserialization. + /// + protected StringTypeConverterException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } } } \ No newline at end of file diff --git a/src/Xtz.StronglyTyped/TypeConverters/StronglyTypedJsonConverter.cs b/src/Xtz.StronglyTyped/TypeConverters/StronglyTypedJsonConverter.cs index 20835b5..df41d4d 100644 --- a/src/Xtz.StronglyTyped/TypeConverters/StronglyTypedJsonConverter.cs +++ b/src/Xtz.StronglyTyped/TypeConverters/StronglyTypedJsonConverter.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Text.Json; using System.Text.Json.Serialization; +using System.Xml; namespace Xtz.StronglyTyped.TypeConverters { @@ -13,12 +14,32 @@ public override bool CanConvert(Type typeToConvert) return typeof(IStronglyTyped).IsAssignableFrom(typeToConvert); } - public override TStronglyTyped? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override TStronglyTyped Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var stringValue = reader.GetString(); - var typeConverter = TypeDescriptor.GetConverter(typeToConvert); + var typeConverter = TypeDescriptor.GetConverter(typeToConvert) as ICustomTypeConverter; + + if (typeConverter!.InnerType == typeof(TimeSpan)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(XmlConvert.ToTimeSpan(reader.GetString()!))!; + } + + if (typeConverter.InnerType == typeof(DateTime)) + { + return StronglyTypedJsonConverter.ReadDateTime(reader, typeConverter); + } + + if (reader.TokenType is JsonTokenType.True or JsonTokenType.False) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetBoolean()!)!; + } + + if (reader.TokenType == JsonTokenType.Number) + { + return StronglyTypedJsonConverter.ReadNumber(reader, typeConverter); + } - return (TStronglyTyped)typeConverter.ConvertFrom(stringValue); + var stringValue = reader.GetString(); + return (TStronglyTyped)typeConverter.ConvertFrom(stringValue!)!; } public override void Write(Utf8JsonWriter writer, TStronglyTyped? value, JsonSerializerOptions options) @@ -39,17 +60,90 @@ public override void Write(Utf8JsonWriter writer, TStronglyTyped? value, JsonSer return; } - if (TryWriteNumber(value, customTypeConverter.InnerType, writer)) - { - return; - } + if (TryWriteNumber(value, customTypeConverter.InnerType, writer)) return; } var stringValue = typeConverter.ConvertTo(value, typeof(string)) as string; writer.WriteStringValue(stringValue); } - private bool TryWriteNumber(IStronglyTyped value, Type innerType, Utf8JsonWriter writer) + private static TStronglyTyped ReadNumber(Utf8JsonReader reader, ICustomTypeConverter typeConverter) + { + if (typeConverter.InnerType == typeof(int)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetInt32())!; + } + + if (typeConverter.InnerType == typeof(float)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetSingle())!; + } + + if (typeConverter.InnerType == typeof(decimal)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetDecimal())!; + } + + if (typeConverter.InnerType == typeof(long)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetInt64())!; + } + + if (typeConverter.InnerType == typeof(double)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetDouble())!; + } + + if (typeConverter.InnerType == typeof(byte)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetByte())!; + } + + if (typeConverter.InnerType == typeof(sbyte)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetSByte())!; + } + + if (typeConverter.InnerType == typeof(short)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetInt16())!; + } + + if (typeConverter.InnerType == typeof(uint)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetUInt32())!; + } + + if (typeConverter.InnerType == typeof(ulong)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetUInt64())!; + } + + if (typeConverter.InnerType == typeof(ushort)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(reader.GetUInt16())!; + } + + throw new JsonConverterException(typeConverter.StrongType, $"Can't convert value to '{typeConverter.StrongType.FullName}'"); + } + + private static TStronglyTyped ReadDateTime(Utf8JsonReader reader, ICustomTypeConverter typeConverter) + { + if (reader.TryGetDateTime(out var dateTimeValue)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(dateTimeValue)!; + } + + var stringValue = reader.GetString(); + if (DateTime.TryParse(stringValue, out var dateTimeValue2)) + { + return (TStronglyTyped)typeConverter.ConvertFrom(dateTimeValue2)!; + } + + throw new JsonConverterException(typeConverter.StrongType, $"Can't convert from '{stringValue}' to '{typeConverter.StrongType.FullName}'"); + } + + private static bool TryWriteNumber(IStronglyTyped value, Type innerType, Utf8JsonWriter writer) { if (innerType == typeof(decimal)) { @@ -131,4 +225,4 @@ private bool TryWriteNumber(IStronglyTyped value, Type innerType, Utf8JsonWriter return false; } } -} \ No newline at end of file +} diff --git a/src/Xtz.StronglyTyped/TypeConverters/TypeConverterException.cs b/src/Xtz.StronglyTyped/TypeConverters/TypeConverterException.cs index 891434b..a35911c 100644 --- a/src/Xtz.StronglyTyped/TypeConverters/TypeConverterException.cs +++ b/src/Xtz.StronglyTyped/TypeConverters/TypeConverterException.cs @@ -1,16 +1,28 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Xtz.StronglyTyped.TypeConverters { [ExcludeFromCodeCoverage] + [Serializable] public class TypeConverterException : StronglyTypedException { - public TypeConverterException(Type type, string errorMessage) : base(type, errorMessage) + public TypeConverterException(Type type, string errorMessage) + : base(type, errorMessage) { } - public TypeConverterException(Type type, string errorMessage, Exception innerException) : base(type, errorMessage, innerException) + public TypeConverterException(Type type, string errorMessage, Exception innerException) + : base(type, errorMessage, innerException) + { + } + + /// + /// Constructor is used for deserialization. + /// + protected TypeConverterException(SerializationInfo info, StreamingContext context) + : base(info, context) { } } diff --git a/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj b/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj index 5fdbcaa..b977a13 100644 --- a/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj +++ b/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj @@ -8,7 +8,7 @@ Xtz.StronglyTyped - 0.19.0 + 0.23.0 true snupkg Vlad DX @@ -33,11 +33,44 @@ Make compiler your friend, introduce semantics to your code. true + + true + latest + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj.DotSettings b/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj.DotSettings new file mode 100644 index 0000000..30e1370 --- /dev/null +++ b/src/Xtz.StronglyTyped/Xtz.StronglyTyped.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file