diff --git a/Ardalis.Specification.sln b/Ardalis.Specification.sln index 39d30f27..2c7ffca9 100644 --- a/Ardalis.Specification.sln +++ b/Ardalis.Specification.sln @@ -5,11 +5,11 @@ VisualStudioVersion = 17.0.31612.314 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification", "Specification\src\Ardalis.Specification\Ardalis.Specification.csproj", "{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.UnitTests", "Specification\tests\Ardalis.Specification.UnitTests\Ardalis.Specification.UnitTests.csproj", "{85D42214-D223-4F13-9A19-9CFA0D3C1981}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.Tests", "Specification\tests\Ardalis.Specification.Tests\Ardalis.Specification.Tests.csproj", "{85D42214-D223-4F13-9A19-9CFA0D3C1981}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFrameworkCore", "Specification.EntityFrameworkCore\src\Ardalis.Specification.EntityFrameworkCore\Ardalis.Specification.EntityFrameworkCore.csproj", "{5EB4ADA4-5258-4964-BD7D-11D4F926E344}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFrameworkCore.IntegrationTests", "Specification.EntityFrameworkCore\tests\Ardalis.Specification.EntityFrameworkCore.IntegrationTests\Ardalis.Specification.EntityFrameworkCore.IntegrationTests.csproj", "{5AFD1454-E625-451D-A615-CEB7BB09AA65}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFrameworkCore.Tests", "Specification.EntityFrameworkCore\tests\Ardalis.Specification.EntityFrameworkCore.Tests\Ardalis.Specification.EntityFrameworkCore.Tests.csproj", "{5AFD1454-E625-451D-A615-CEB7BB09AA65}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{A74A4C02-5F33-4667-A627-78A5B295A61F}" ProjectSection(SolutionItems) = preProject @@ -33,7 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample", "Sample", "{1FCFDF EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFramework6", "Specification.EntityFramework6\src\Ardalis.Specification.EntityFramework6\Ardalis.Specification.EntityFramework6.csproj", "{37EC09C7-702D-4539-B98D-F67B15E1E6CE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFramework6.IntegrationTests", "Specification.EntityFramework6\tests\Ardalis.Specification.EntityFramework6.IntegrationTests\Ardalis.Specification.EntityFramework6.IntegrationTests.csproj", "{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.EntityFramework6.Tests", "Specification.EntityFramework6\tests\Ardalis.Specification.EntityFramework6.Tests\Ardalis.Specification.EntityFramework6.Tests.csproj", "{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specification", "Specification", "{9CA909ED-E3A6-4D76-A4F3-250E93942813}" EndProject diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/ReadCollection.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/ReadCollection.cs deleted file mode 100644 index 00803d03..00000000 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/ReadCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Xunit; - -namespace Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture.Collections; - -[CollectionDefinition("ReadCollection")] -public class ReadCollection : ICollectionFixture -{ - public ReadCollection() - { - - } -} diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/WriteCollection.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/WriteCollection.cs deleted file mode 100644 index 9b46bf83..00000000 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/Collections/WriteCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Xunit; - -namespace Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture.Collections; - -[CollectionDefinition("WriteCollection")] -public class WriteCollection : ICollectionFixture -{ - public WriteCollection() - { - - } -} diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/DatabaseFixture.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/DatabaseFixture.cs deleted file mode 100644 index 98fbd65c..00000000 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/DatabaseFixture.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using MartinCostello.SqlLocalDb; -using System; - -namespace Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; - -public class DatabaseFixture : IDisposable -{ - public string ConnectionString { get; } - - public DatabaseFixture() - { - var databaseName = $"SpecificationTestsDB_{Guid.NewGuid().ToString().Replace('-', '_')}"; - - using (var localDB = new SqlLocalDbApi()) - { - ConnectionString = localDB.IsLocalDBInstalled() - ? $"Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog={databaseName};Integrated Security=SSPI;MultipleActiveResultSets=True;Connection Timeout=300" - : $"Data Source=databaseEF;Initial Catalog={databaseName};PersistSecurityInfo=True;User ID=sa;Password=P@ssW0rd!;"; - } - - Console.WriteLine($"Connection string: {ConnectionString}"); - - using var dbContext = new TestDbContext(ConnectionString); - dbContext.Database.Delete(); - dbContext.Database.Create(); - - dbContext.Countries.AddRange(CountrySeed.Get()); - dbContext.Companies.AddRange(CompanySeed.Get()); - dbContext.Stores.AddRange(StoreSeed.Get()); - dbContext.Addresses.AddRange(AddressSeed.Get()); - dbContext.Products.AddRange(ProductSeed.Get()); - - dbContext.SaveChanges(); - } - - public void Dispose() - { - using var dbContext = new TestDbContext(ConnectionString); - dbContext.Database.Delete(); - GC.SuppressFinalize(this); - } -} diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Ardalis.Specification.EntityFramework6.IntegrationTests.csproj b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Ardalis.Specification.EntityFramework6.Tests.csproj similarity index 80% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Ardalis.Specification.EntityFramework6.IntegrationTests.csproj rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Ardalis.Specification.EntityFramework6.Tests.csproj index 9720699c..e6af186e 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Ardalis.Specification.EntityFramework6.IntegrationTests.csproj +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Ardalis.Specification.EntityFramework6.Tests.csproj @@ -2,7 +2,8 @@ net472;net8.0 - 12.0 + 13.0 + enable Library false @@ -14,6 +15,7 @@ + @@ -25,11 +27,15 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/ReadCollection.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/ReadCollection.cs new file mode 100644 index 00000000..f0a1f5b4 --- /dev/null +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/ReadCollection.cs @@ -0,0 +1,10 @@ +namespace Tests.Fixture; + +[CollectionDefinition("ReadCollection")] +public class ReadCollection : ICollectionFixture +{ + public ReadCollection() + { + + } +} diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/WriteCollection.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/WriteCollection.cs new file mode 100644 index 00000000..816d3a40 --- /dev/null +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Collections/WriteCollection.cs @@ -0,0 +1,10 @@ +namespace Tests.Fixture; + +[CollectionDefinition("WriteCollection")] +public class WriteCollection : ICollectionFixture +{ + public WriteCollection() + { + + } +} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Address.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Address.cs similarity index 80% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Address.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Address.cs index 93b8763e..6256bc51 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Address.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Address.cs @@ -1,4 +1,4 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Entities; +namespace Tests.Fixture; public class Address { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Company.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Company.cs similarity index 71% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Company.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Company.cs index f4dd0588..265c16ab 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Company.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Company.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities; +namespace Tests.Fixture; public class Company { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Country.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Country.cs similarity index 63% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Country.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Country.cs index 0a778f4a..45a6aae9 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Country.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Country.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities; +namespace Tests.Fixture; public class Country { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Product.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Product.cs similarity index 73% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Product.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Product.cs index bc78bf00..b184aa5c 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Product.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Product.cs @@ -1,4 +1,4 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Entities; +namespace Tests.Fixture; public class Product { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/AddressSeed.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/AddressSeed.cs similarity index 83% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/AddressSeed.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/AddressSeed.cs index a0c0a5a4..71cca869 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/AddressSeed.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/AddressSeed.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; +namespace Tests.Fixture; public class AddressSeed { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CompanySeed.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CompanySeed.cs similarity index 88% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CompanySeed.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CompanySeed.cs index 3b93bd1c..ccc3d31e 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CompanySeed.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CompanySeed.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; +namespace Tests.Fixture; public class CompanySeed { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CountrySeed.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CountrySeed.cs similarity index 78% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CountrySeed.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CountrySeed.cs index 0bf29916..8dacaf08 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/CountrySeed.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/CountrySeed.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; +namespace Tests.Fixture; public class CountrySeed { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/ProductSeed.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/ProductSeed.cs similarity index 87% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/ProductSeed.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/ProductSeed.cs index 9007c84c..c0798a87 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/ProductSeed.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/ProductSeed.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; +namespace Tests.Fixture; public class ProductSeed { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/StoreSeed.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/StoreSeed.cs similarity index 95% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/StoreSeed.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/StoreSeed.cs index f6423f83..49168ba4 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Seeds/StoreSeed.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Seeds/StoreSeed.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; +namespace Tests.Fixture; public class StoreSeed { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Store.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Store.cs similarity index 82% rename from Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Store.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Store.cs index 29e4b3b0..94940810 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Entities/Store.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/Entities/Store.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Entities; +namespace Tests.Fixture; public class Store { diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/RepositoryOfT.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/RepositoryOfT.cs similarity index 75% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/RepositoryOfT.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/RepositoryOfT.cs index ea2832c1..c598d7af 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/RepositoryOfT.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/RepositoryOfT.cs @@ -1,11 +1,11 @@ -namespace Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; +namespace Tests.Fixture; /// public class Repository : RepositoryBase where T : class { protected readonly TestDbContext dbContext; - public Repository(TestDbContext dbContext) : this(dbContext, EntityFramework6.SpecificationEvaluator.Default) + public Repository(TestDbContext dbContext) : this(dbContext, Ardalis.Specification.EntityFramework6.SpecificationEvaluator.Default) { } diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/TestDbContext.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestDbContext.cs similarity index 66% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/TestDbContext.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestDbContext.cs index dcf288ff..eeee2bd3 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Fixture/TestDbContext.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestDbContext.cs @@ -1,8 +1,7 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities; -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; +namespace Tests.Fixture; public class TestDbContext : DbContext { @@ -10,11 +9,11 @@ public TestDbContext(string connectionString) : base(connectionString) { } - public virtual DbSet Countries { get; set; } - public virtual DbSet Companies { get; set; } - public virtual DbSet Stores { get; set; } - public virtual DbSet
Addresses { get; set; } - public virtual DbSet Products { get; set; } + public virtual DbSet Countries { get; set; } = null!; + public virtual DbSet Companies { get; set; } = null!; + public virtual DbSet Stores { get; set; } = null!; + public virtual DbSet
Addresses { get; set; } = null!; + public virtual DbSet Products { get; set; } = null!; protected override void OnModelCreating(DbModelBuilder modelBuilder) { diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestFactory.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestFactory.cs new file mode 100644 index 00000000..55593138 --- /dev/null +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Fixture/TestFactory.cs @@ -0,0 +1,64 @@ +using MartinCostello.SqlLocalDb; +using System; +using System.Threading.Tasks; +using Testcontainers.MsSql; + +namespace Tests.Fixture; + +public class TestFactory : IAsyncLifetime +{ + // Flag to force using Docker SQL Server. Update it manually if you want to avoid localDb locally. + private const bool _forceDocker = false; + private MsSqlContainer? _dbContainer = null; + + public string ConnectionString { get; private set; } = null!; + + public async Task InitializeAsync() + { + using (var localDB = new SqlLocalDbApi()) + { + if (_forceDocker || !localDB.IsLocalDBInstalled()) + { + _dbContainer = CreateContainer(); + await _dbContainer.StartAsync(); + ConnectionString = _dbContainer.GetConnectionString(); + } + else + { + var databaseName = $"SpecificationEF6TestsDB_{Guid.NewGuid().ToString().Replace('-', '_')}"; + ConnectionString = $"Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog={databaseName};Integrated Security=SSPI;TrustServerCertificate=True;"; + } + } + + using var dbContext = new TestDbContext(ConnectionString); + + dbContext.Database.CreateIfNotExists(); + + dbContext.Countries.AddRange(CountrySeed.Get()); + dbContext.Companies.AddRange(CompanySeed.Get()); + dbContext.Stores.AddRange(StoreSeed.Get()); + dbContext.Addresses.AddRange(AddressSeed.Get()); + dbContext.Products.AddRange(ProductSeed.Get()); + + dbContext.SaveChanges(); + } + + public async Task DisposeAsync() + { + if (_dbContainer is not null) + { + await _dbContainer.StopAsync(); + } + else + { + using var dbContext = new TestDbContext(ConnectionString); + dbContext.Database.Delete(); + } + } + + private static MsSqlContainer CreateContainer() => new MsSqlBuilder() + .WithImage("mcr.microsoft.com/mssql/server:2022-latest") + //.WithName("SpecificationEFCoreTestsDB") + .WithPassword("P@ssW0rd!") + .Build(); +} diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/GlobalUsings.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/GlobalUsings.cs new file mode 100644 index 00000000..0dd55c2b --- /dev/null +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/GlobalUsings.cs @@ -0,0 +1,7 @@ +global using Ardalis.Specification; +global using Ardalis.Specification.EntityFramework6; +global using FluentAssertions; +global using System.Collections.Generic; +global using System.Linq; +global using Tests.Fixture; +global using Xunit; diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Properties/AssemblyInfo.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Properties/AssemblyInfo.cs similarity index 100% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/Properties/AssemblyInfo.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/Properties/AssemblyInfo.cs diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_AnyAsync.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_AnyAsync.cs similarity index 58% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_AnyAsync.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_AnyAsync.cs index 0511e44e..a9faac38 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_AnyAsync.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_AnyAsync.cs @@ -1,21 +1,15 @@ -using Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using System.Threading.Tasks; -using Xunit; +using System.Threading.Tasks; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests; +namespace Tests; [Collection("ReadCollection")] public class RepositoryOfT_AnyAsync { private readonly string _connectionString; - public RepositoryOfT_AnyAsync(DatabaseFixture fixture) + public RepositoryOfT_AnyAsync(TestFactory factory) { - _connectionString = fixture.ConnectionString; + _connectionString = factory.ConnectionString; } [Fact] @@ -34,8 +28,10 @@ public async Task ReturnsTrue_GivenStoreByIdSpecWithValidStore() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID); - var result = await repo.AnyAsync(new StoreByIdSpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.AnyAsync(spec); result.Should().BeTrue(); } @@ -45,8 +41,10 @@ public async Task ReturnsFalse_GivenStoreByIdSpecWithInvalidStore() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == 0); - var result = await repo.AnyAsync(new StoreByIdSpec(0)); + var result = await repo.AnyAsync(spec); result.Should().BeFalse(); } diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_DeleteRangeAsync.cs similarity index 69% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_DeleteRangeAsync.cs index a805fb73..27332910 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_DeleteRangeAsync.cs @@ -1,71 +1,78 @@ -using Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using System.Threading.Tasks; -using Xunit; +using System.Threading.Tasks; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests; +namespace Tests; [Collection("WriteCollection")] public class RepositoryOfT_DeleteRangeAsync { - private readonly string _connectionString; + private readonly string _connectionString; - public RepositoryOfT_DeleteRangeAsync(DatabaseFixture fixture) + public RepositoryOfT_DeleteRangeAsync(TestFactory factory) { - _connectionString = fixture.ConnectionString; - } - + _connectionString = factory.ConnectionString; + } + [Fact] public virtual async Task DeletesProductWithStoreIdOne_GivenProductByStoreIdSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext, SpecificationEvaluator.Default); - - await repo.DeleteRangeAsync(new ProductByStoreIdSpec(1)); + var spec = new Specification(); + spec.Query.Where(x => x.StoreId == 1); + + await repo.DeleteRangeAsync(spec); + + var products = await repo.ListAsync(); + products.Should().NotBeNullOrEmpty(); + products.Should().NotContain(e => e.StoreId == 1); + } - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.StoreId == 1); - } - [Fact] public virtual async Task DeletesProductWithIdOne_GivenProductByIdSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext, SpecificationEvaluator.Default); - - await repo.DeleteRangeAsync(new ProductByIdSpec(2)); + var spec = new Specification(); + spec.Query.Where(x => x.Id == 2); + + await repo.DeleteRangeAsync(spec); + + var products = await repo.ListAsync(); + products.Should().NotBeNullOrEmpty(); + products.Should().NotContain(e => e.Id == 2); + } - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 2); - } - [Fact] public virtual async Task DeletesProductWithIdOne_GivenProductByIdAsUntrackedWithIdentityResolutionSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext, SpecificationEvaluator.Default); - - await repo.DeleteRangeAsync(new ProductByIdAsUntrackedWithIdentityResolutionSpec(3)); + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 3) + .AsNoTrackingWithIdentityResolution(); + + await repo.DeleteRangeAsync(spec); + + var products = await repo.ListAsync(); + products.Should().NotBeNullOrEmpty(); + products.Should().NotContain(e => e.Id == 3); + } - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 3); - } - [Fact] public virtual async Task DeletesProductWithIdOne_GivenProductByIdAsTrackedSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext, SpecificationEvaluator.Default); - - await repo.DeleteRangeAsync(new ProductByIdAsTrackedSpec(4)); + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 4) + .AsTracking(); + + await repo.DeleteRangeAsync(spec); - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 4); + var products = await repo.ListAsync(); + products.Should().NotBeNullOrEmpty(); + products.Should().NotContain(e => e.Id == 4); } } diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetById.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetById.cs similarity index 66% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetById.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetById.cs index da686046..7ca96d10 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetById.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetById.cs @@ -1,20 +1,15 @@ -using Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using FluentAssertions; -using System.Threading.Tasks; -using Xunit; +using System.Threading.Tasks; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests; +namespace Tests; [Collection("ReadCollection")] public class RepositoryOfT_GetById { private readonly string _connectionString; - public RepositoryOfT_GetById(DatabaseFixture fixture) + public RepositoryOfT_GetById(TestFactory factory) { - _connectionString = fixture.ConnectionString; + _connectionString = factory.ConnectionString; } [Fact] diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetBySpec.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetBySpec.cs similarity index 65% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetBySpec.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetBySpec.cs index 98544872..675a9aac 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_GetBySpec.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_GetBySpec.cs @@ -1,23 +1,16 @@ -using Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using System.Data.Entity; -using System.Linq; +using System.Data.Entity; using System.Threading.Tasks; -using Xunit; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests; +namespace Tests; [Collection("ReadCollection")] public class RepositoryOfT_GetBySpec { private readonly string _connectionString; - public RepositoryOfT_GetBySpec(DatabaseFixture fixture) + public RepositoryOfT_GetBySpec(TestFactory factory) { - _connectionString = fixture.ConnectionString; + _connectionString = factory.ConnectionString; } [Fact] @@ -25,8 +18,11 @@ public async Task ReturnsStoreWithProducts_GivenStoreByIdIncludeProductsSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID) + .Include(x => x.Products); - var result = await repo.GetBySpecAsync(new StoreByIdIncludeProductsSpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(StoreSeed.VALID_STORE_NAME); @@ -38,8 +34,11 @@ public async Task ReturnsStoreWithAddress_GivenStoreByIdIncludeAddressSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID) + .Include(x => x.Address); - var result = await repo.GetBySpecAsync(new StoreByIdIncludeAddressSpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(StoreSeed.VALID_STORE_NAME); @@ -51,8 +50,12 @@ public async Task ReturnsStoreWithAddressAndProduct_GivenStoreByIdIncludeAddress { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID) + .Include(x => x.Address) + .Include(x => x.Products); - var result = await repo.GetBySpecAsync(new StoreByIdIncludeAddressAndProductsSpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(StoreSeed.VALID_STORE_NAME); @@ -65,8 +68,11 @@ public async Task ReturnsStoreWithProducts_GivenStoreByIdIncludeProductsUsingStr { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID) + .Include(nameof(Store.Products)); - var result = await repo.GetBySpecAsync(new StoreByIdIncludeProductsUsingStringSpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(StoreSeed.VALID_STORE_NAME); @@ -78,8 +84,12 @@ public async Task ReturnsCompanyWithStoresAndAddress_GivenCompanyByIdIncludeStor { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == CompanySeed.VALID_COMPANY_ID) + .Include(x => x.Stores) + .ThenInclude(x => x.Address); - var result = await repo.GetBySpecAsync(new CompanyByIdIncludeStoresThenIncludeAddressSpec(CompanySeed.VALID_COMPANY_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); @@ -92,8 +102,12 @@ public async Task ReturnsCompanyWithStoresAndProducts_GivenCompanyByIdIncludeSto { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == CompanySeed.VALID_COMPANY_ID) + .Include(x => x.Stores) + .ThenInclude(x => x.Products); - var result = await repo.GetBySpecAsync(new CompanyByIdIncludeStoresThenIncludeProductsSpec(CompanySeed.VALID_COMPANY_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); @@ -106,8 +120,11 @@ public async Task ReturnsUntrackedCompany_GivenCompanyByIdAsUntrackedSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == CompanySeed.VALID_COMPANY_ID) + .AsNoTracking(); - var result = await repo.GetBySpecAsync(new CompanyByIdAsUntrackedSpec(CompanySeed.VALID_COMPANY_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result?.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); @@ -119,8 +136,12 @@ public async Task ReturnsStoreWithCompanyAndCountryAndStoresForCompany_GivenStor { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Where(x => x.Id == StoreSeed.VALID_STORE_ID) + .Include(x => x.Company).ThenInclude(x => x!.Country) + .Include(x => x.Company).ThenInclude(x => x!.Stores).ThenInclude(x => x.Products); - var result = await repo.GetBySpecAsync(new StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec(StoreSeed.VALID_STORE_ID)); + var result = await repo.GetBySpecAsync(spec); result.Should().NotBeNull(); result.Name.Should().Be(StoreSeed.VALID_STORE_NAME); diff --git a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_ListAsync.cs b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_ListAsync.cs similarity index 72% rename from Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_ListAsync.cs rename to Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_ListAsync.cs index 45eaa465..8cbfd0dd 100644 --- a/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.IntegrationTests/RepositoryOfT_ListAsync.cs +++ b/Specification.EntityFramework6/tests/Ardalis.Specification.EntityFramework6.Tests/RepositoryOfT_ListAsync.cs @@ -1,22 +1,15 @@ -using Ardalis.Specification.EntityFramework6.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using System.Linq; -using System.Threading.Tasks; -using Xunit; +using System.Threading.Tasks; -namespace Ardalis.Specification.EntityFramework6.IntegrationTests; +namespace Tests; [Collection("ReadCollection")] public class RepositoryOfT_ListAsync { private readonly string _connectionString; - public RepositoryOfT_ListAsync(DatabaseFixture fixture) + public RepositoryOfT_ListAsync(TestFactory factory) { - _connectionString = fixture.ConnectionString; + _connectionString = factory.ConnectionString; } [Fact] @@ -24,8 +17,10 @@ public async Task ReturnsStoreWithProducts_GivenStoreIncludeProductsSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Include(x => x.Products); - var result = await repo.ListAsync(new StoreIncludeProductsSpec()); + var result = await repo.ListAsync(spec); result.Should().NotBeNull(); result.Should().NotBeEmpty(); @@ -37,8 +32,10 @@ public async Task ReturnsStoreWithAddress_GivenStoreIncludeAddressSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query.Include(x => x.Address); - var result = await repo.ListAsync(new StoreIncludeAddressSpec()); + var result = await repo.ListAsync(spec); result.Should().NotBeNull(); result.Should().NotBeEmpty(); @@ -50,8 +47,12 @@ public async Task ReturnsStoreWithAddressAndProduct_GivenStoreIncludeAddressAndP { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); + var spec = new Specification(); + spec.Query + .Include(x => x.Products) + .Include(x => x!.Address); - var result = await repo.ListAsync(new StoreIncludeAddressAndProductsSpec()); + var result = await repo.ListAsync(spec); result.Should().NotBeNull(); result.Should().NotBeEmpty(); @@ -64,9 +65,10 @@ public async Task ReturnsStoreWithIdFrom15To30_GivenStoresByIdListSpec() { using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var ids = Enumerable.Range(15, 16); - var spec = new StoresByIdListSpec(ids); + + var spec = new Specification(); + spec.Query.Where(x => ids.Contains(x.Id)); var stores = await repo.ListAsync(spec); @@ -84,7 +86,12 @@ public async Task ReturnsSecondPageOfStoreNames_GivenStoreNamesPaginatedSpec() var take = 10; // pagesize 10 var skip = (2 - 1) * 10; // page 2 - var spec = new StoreNamesPaginatedSpec(skip, take); + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id) + .Skip(skip) + .Take(take); + spec.Query.Select(x => x.Name); var storeNames = await repo.ListAsync(spec); @@ -102,7 +109,11 @@ public async Task ReturnsSecondPageOfStores_GivenStoresPaginatedSpec() var take = 10; // pagesize 10 var skip = (2 - 1) * 10; // page 2 - var spec = new StoresPaginatedSpec(skip, take); + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id) + .Skip(skip) + .Take(take); var stores = await repo.ListAsync(spec); @@ -117,7 +128,10 @@ public async Task ReturnsOrderStoresByNameDescForCompanyWithId2_GivenStoresByCom using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var spec = new StoresByCompanyOrderedDescByNameSpec(2); + var spec = new Specification(); + spec.Query + .Where(x => x.CompanyId == 2) + .OrderByDescending(x => x.Name); var stores = await repo.ListAsync(spec); @@ -131,7 +145,11 @@ public async Task ReturnsOrderStoresByNameDescThenByIdForCompanyWithId2_GivenSto using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var spec = new StoresByCompanyOrderedDescByNameThenByIdSpec(2); + var spec = new Specification(); + spec.Query + .Where(x => x.CompanyId == 2) + .OrderByDescending(x => x.Name) + .ThenBy(x => x.Id); var stores = await repo.ListAsync(spec); @@ -148,7 +166,11 @@ public async Task ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompan var take = 10; // pagesize 10 var skip = (2 - 1) * 10; // page 2 - var spec = new StoresByCompanyPaginatedOrderedDescByNameSpec(2, skip, take); + var spec = new Specification(); + spec.Query.Where(x => x.CompanyId == 2) + .Skip(skip) + .Take(take) + .OrderByDescending(x => x.Name); var stores = await repo.ListAsync(spec); @@ -166,7 +188,12 @@ public async Task ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompan var take = 10; // pagesize 10 var skip = (2 - 1) * 10; // page 2 - var spec = new StoresByCompanyPaginatedSpec(2, skip, take); + var spec = new Specification(); + spec.Query + .Where(x => x.CompanyId == 2) + .OrderBy(x => x.CompanyId) + .Skip(skip) + .Take(take); var stores = await repo.ListAsync(spec); @@ -181,7 +208,8 @@ public async Task ReturnsOrderedStores_GivenStoresOrderedSpecByName() using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var spec = new StoresOrderedSpecByName(); + var spec = new Specification(); + spec.Query.OrderBy(x => x.Name); var stores = await repo.ListAsync(spec); @@ -195,7 +223,8 @@ public async Task ReturnsOrderedStores_GivenStoresOrderedDescendingByNameSpec() using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var spec = new StoresOrderedDescendingByNameSpec(); + var spec = new Specification(); + spec.Query.OrderByDescending(x => x.Name); var stores = await repo.ListAsync(spec); @@ -209,7 +238,12 @@ public async Task ReturnsStoreContainingCity1_GivenStoreIncludeProductsSpec() using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var result = await repo.ListAsync(new StoreSearchByNameOrCitySpec(StoreSeed.VALID_Search_City_Key)); + var spec = new Specification(); + spec.Query + .Search(x => x.Name!, "%" + StoreSeed.VALID_Search_City_Key + "%") + .Search(x => x.City!, "%" + StoreSeed.VALID_Search_City_Key + "%"); + + var result = await repo.ListAsync(spec); result.Should().NotBeNull(); result.Should().ContainSingle(); @@ -223,7 +257,11 @@ public virtual async Task ReturnsAllProducts_GivenStoreSelectManyProductsSpec() using var dbContext = new TestDbContext(_connectionString); var repo = new Repository(dbContext); - var result = await repo.ListAsync(new StoreProductNamesSpec()); + var spec = new Specification(); + spec.Query + .SelectMany(s => s.Products.Select(p => p.Name)); + + var result = await repo.ListAsync(spec); result.Should().NotBeNull(); result.Should().HaveCount(ProductSeed.TOTAL_PRODUCT_COUNT); diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/ContextFactoryRepositoryBaseOfTTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/ContextFactoryRepositoryBaseOfTTests.cs deleted file mode 100644 index 3e0f48be..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/ContextFactoryRepositoryBaseOfTTests.cs +++ /dev/null @@ -1,190 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -public class ContextFactoryRepositoryBaseOfTTests : IClassFixture -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ContextFactoryRepository _repository; - private readonly IServiceProvider _serviceProvider; - private readonly Random _random = new Random(); - - public ContextFactoryRepositoryBaseOfTTests(DatabaseFixture fixture) - { - _dbContextOptions = fixture.DbContextOptions; - - _serviceProvider = new ServiceCollection() - .AddDbContextFactory((builder => builder.UseSqlServer(fixture.ConnectionString)), ServiceLifetime.Transient) - .BuildServiceProvider(); - - var contextFactory = _serviceProvider.GetService>(); - _repository = new ContextFactoryRepository(contextFactory); - } - - [Fact] - public async Task Saves_new_entity() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test save new company name", - CountryId = country.Id - }; - - await _repository.AddAsync(company); - Assert.NotEqual(0, company.Id); - } - - [Fact] - public async Task Updates_existing_entity() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update existing company name", - CountryId = country.Id - }; - await _repository.AddAsync(company); - - var existingCompany = await _repository.GetByIdAsync(company.Id); - existingCompany.Name = "Updated company name"; - await _repository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - } - - [Fact] - public async Task Updates_existing_entity_across_context_instances() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var contextFactory = _serviceProvider.GetService>(); - var companyRetrievalRepository = new ContextFactoryRepository(contextFactory); - var companySaveRepository = new ContextFactoryRepository(contextFactory); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update existing company name", - CountryId = country.Id - }; - await _repository.AddAsync(company); - - var existingCompany = await companyRetrievalRepository.GetByIdAsync(company.Id); - existingCompany.Name = "Updated company name"; - await companySaveRepository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - } - - [Fact] - public async Task Updates_graph() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update graph", - CountryId = country.Id - }; - var store = new Store - { - Id = _random.Next(1000, 9999), - Name = "Store Number 1" - }; - company.Stores.Add(store); - - await _repository.AddAsync(company); - - var spec = new CompanyByIdIncludeStoresSpec(company.Id); - var existingCompany = await _repository.FirstOrDefaultAsync(spec); - existingCompany.Name = "Updated company name"; - var existingStore = existingCompany.Stores.FirstOrDefault(); - existingStore.Name = "Updated Store Name"; - - await _repository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - - var validationStore = await dbContext.Stores.FirstOrDefaultAsync(x => x.CompanyId == company.Id); - Assert.Equal(validationStore.Name, existingStore.Name); - } - - [Fact] - public async Task Updates_graph_across_context_instances() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var contextFactory = _serviceProvider.GetService>(); - var companyRetrievalRepository = new ContextFactoryRepository(contextFactory); - var companySaveRepository = new ContextFactoryRepository(contextFactory); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update graph", - CountryId = country.Id - }; - var store = new Store - { - Id = _random.Next(1000, 9999), - Name = "Store Number 1" - }; - company.Stores.Add(store); - - await _repository.AddAsync(company); - - var spec = new CompanyByIdIncludeStoresSpec(company.Id); - var existingCompany = await companyRetrievalRepository.FirstOrDefaultAsync(spec); - existingCompany.Name = "Updated company name"; - var existingStore = existingCompany.Stores.FirstOrDefault(); - existingStore.Name = "Updated Store Name"; - - await companySaveRepository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - - var validationStore = await dbContext.Stores.FirstOrDefaultAsync(x => x.CompanyId == company.Id); - Assert.Equal(validationStore.Name, existingStore.Name); - } - - [Fact] - public async Task Deletes_entity() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update graph", - CountryId = country.Id - }; - await _repository.AddAsync(company); - - var companyId = company.Id; - await _repository.DeleteAsync(company); - - var validationCompany = await _repository.GetByIdAsync(companyId); - Assert.Null(validationCompany); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/EFRepositoryFactoryTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/EFRepositoryFactoryTests.cs deleted file mode 100644 index a305c9be..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/EFRepositoryFactoryTests.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -public class EFRepositoryFactoryTests : IClassFixture -{ - private readonly DbContextOptions _dbContextOptions; - private readonly IRepositoryFactory> _repositoryFactory; - private readonly IDbContextFactory _contextFactory; - private readonly IServiceProvider _serviceProvider; - private readonly Random _random = new Random(); - - public EFRepositoryFactoryTests(DatabaseFixture fixture) - { - _dbContextOptions = fixture.DbContextOptions; - - _serviceProvider = new ServiceCollection() - .AddDbContextFactory((builder => builder.UseSqlServer(fixture.ConnectionString)), ServiceLifetime.Transient) - .BuildServiceProvider(); - - _contextFactory = _serviceProvider.GetService>(); - _repositoryFactory = new EFRepositoryFactory, Repository, TestDbContext>(_contextFactory); - } - - [Fact] - public void CorrectlyInstantiatesRepository() - { - var mockContextFactory = new Mock>(); - mockContextFactory.Setup(x => x.CreateDbContext()) - .Returns(() => new SampleDbContext(new DbContextOptions())); - - var repositoryFactory = new EFRepositoryFactory, MyRepository, SampleDbContext>(mockContextFactory.Object); - - var repository = repositoryFactory.CreateRepository(); - Assert.IsType>(repository); - } - - [Fact] - public async Task Saves_new_entity() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - var repository = _repositoryFactory.CreateRepository(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test save new company name", - CountryId = country.Id - }; - - await repository.AddAsync(company); - Assert.NotEqual(0, company.Id); - } - - [Fact] - public async Task Updates_existing_entity() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - var repository = _repositoryFactory.CreateRepository(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update existing company name", - CountryId = country.Id - }; - await repository.AddAsync(company); - - var existingCompany = await repository.GetByIdAsync(company.Id); - existingCompany.Name = "Updated company name"; - await repository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - } - - [Fact] - public async Task Updates_graph() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var country = await dbContext.Countries.FirstOrDefaultAsync(); - var repository = _repositoryFactory.CreateRepository(); - - var company = new Company - { - Id = _random.Next(1000, 9999), - Name = "Test update graph", - CountryId = country.Id - }; - var store = new Store - { - Id = _random.Next(1000, 9999), - Name = "Store Number 1" - }; - company.Stores.Add(store); - - await repository.AddAsync(company); - - var spec = new CompanyByIdIncludeStoresSpec(company.Id); - var existingCompany = await repository.FirstOrDefaultAsync(spec); - existingCompany.Name = "Updated company name"; - var existingStore = existingCompany.Stores.FirstOrDefault(); - existingStore.Name = "Updated Store Name"; - - await repository.UpdateAsync(existingCompany); - - var validationCompany = await dbContext.Companies.FirstOrDefaultAsync(x => x.Id == company.Id); - Assert.Equal(validationCompany.Name, existingCompany.Name); - - var validationStore = await dbContext.Stores.FirstOrDefaultAsync(x => x.CompanyId == company.Id); - Assert.Equal(validationStore.Name, existingStore.Name); - } - - public record Customer(int Id, string Name); - - public class SampleDbContext : DbContext - { - public DbSet Customers { get; set; } - - public SampleDbContext(DbContextOptions options) - : base(options) - { - } - } - - public interface IRepository : IRepositoryBase where T : class - { - } - - public class MyRepository : RepositoryBase, IRepository where T : class - { - public MyRepository(SampleDbContext dbContext) : base(dbContext) - { - } - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/ReadCollection.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/ReadCollection.cs deleted file mode 100644 index f7b02013..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/ReadCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture.Collections; - -[CollectionDefinition("ReadCollection")] -public class ReadCollection : ICollectionFixture -{ - public ReadCollection() - { - - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/WriteCollection.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/WriteCollection.cs deleted file mode 100644 index 781c034e..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/Collections/WriteCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture.Collections; - -[CollectionDefinition("WriteCollection")] -public class WriteCollection : ICollectionFixture -{ - public WriteCollection() - { - - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/ContextFactoryRepositoryOfT.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/ContextFactoryRepositoryOfT.cs deleted file mode 100644 index a5ff9895..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/ContextFactoryRepositoryOfT.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; - -public class ContextFactoryRepository : ContextFactoryRepositoryBaseOfT - where T : class where TContext : DbContext -{ - public ContextFactoryRepository(IDbContextFactory dbContextFactory) - : base(dbContextFactory) - { - } - - public ContextFactoryRepository(IDbContextFactory dbContextFactory, ISpecificationEvaluator specificationEvaluator) - : base(dbContextFactory, specificationEvaluator) - { - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/DatabaseFixture.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/DatabaseFixture.cs deleted file mode 100644 index ab77fd69..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/DatabaseFixture.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using MartinCostello.SqlLocalDb; -using Microsoft.EntityFrameworkCore; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; - -public class DatabaseFixture : IDisposable -{ - public DbContextOptions DbContextOptions { get; } - public string ConnectionString { get; } - - public DatabaseFixture() - { - var databaseName = $"SpecificationTestsDB_{Guid.NewGuid().ToString().Replace('-', '_')}"; - - using (var localDB = new SqlLocalDbApi()) - { - ConnectionString = localDB.IsLocalDBInstalled() - ? $"Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog={databaseName};Integrated Security=SSPI;MultipleActiveResultSets=True;Connection Timeout=300;Encrypt=False;TrustServerCertificate=True;" - : $"Data Source=databaseEF;Initial Catalog={databaseName};PersistSecurityInfo=True;User ID=sa;Password=P@ssW0rd!;Encrypt=False;TrustServerCertificate=True;"; - } - - Console.WriteLine($"Connection string: {ConnectionString}"); - - DbContextOptions = new DbContextOptionsBuilder() - .UseSqlServer(ConnectionString, x => x.EnableRetryOnFailure()) - .EnableSensitiveDataLogging() - .Options; - - using var dbContext = new TestDbContext(DbContextOptions); - dbContext.Database.EnsureDeleted(); - dbContext.Database.EnsureCreated(); - - dbContext.Countries.AddRange(CountrySeed.Get()); - dbContext.Companies.AddRange(CompanySeed.Get()); - dbContext.Stores.AddRange(StoreSeed.Get()); - dbContext.Addresses.AddRange(AddressSeed.Get()); - dbContext.Products.AddRange(ProductSeed.Get()); - - dbContext.SaveChanges(); - } - - public void Dispose() - { - using var dbContext = new TestDbContext(DbContextOptions); - dbContext.Database.EnsureDeleted(); - GC.SuppressFinalize(this); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/RepositoryOfT.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/RepositoryOfT.cs deleted file mode 100644 index 6c81b2af..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/RepositoryOfT.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; - -/// -public class Repository : RepositoryBase where T : class -{ - protected readonly TestDbContext dbContext; - - public Repository(TestDbContext dbContext) : this(dbContext, EntityFrameworkCore.SpecificationEvaluator.Default) - { - } - - public Repository(TestDbContext dbContext, ISpecificationEvaluator specificationEvaluator) : base(dbContext, specificationEvaluator) - { - this.dbContext = dbContext; - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/TestDbContext.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/TestDbContext.cs deleted file mode 100644 index 23ef01da..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Fixture/TestDbContext.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Microsoft.EntityFrameworkCore; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; - -public class TestDbContext : DbContext -{ - public DbSet Countries => Set(); - public DbSet Companies => Set(); - public DbSet Stores => Set(); - public DbSet
Addresses => Set
(); - public DbSet Products => Set(); - - public TestDbContext(DbContextOptions options) : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity
().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); - - modelBuilder.Entity().HasOne(x => x.Address).WithOne(x => x!.Store!).HasForeignKey
(x => x.StoreId); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AnyAsync.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AnyAsync.cs deleted file mode 100644 index 29599227..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AnyAsync.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("ReadCollection")] -public class RepositoryOfT_AnyAsync : RepositoryOfT_AnyAsync_TestKit -{ - public RepositoryOfT_AnyAsync(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Default) - { - } -} - -[Collection("ReadCollection")] -public class RepositoryOfT_AnyAsync_Cached : RepositoryOfT_AnyAsync_TestKit -{ - public RepositoryOfT_AnyAsync_Cached(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Cached) - { - } -} - -public abstract class RepositoryOfT_AnyAsync_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_AnyAsync_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task ReturnsTrueOnStoresRecords_WithoutSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.AnyAsync(); - - result.Should().BeTrue(); - } - - [Fact] - public virtual async Task ReturnsTrue_GivenStoreByIdSpecWithValidStore() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.AnyAsync(new StoreByIdSpec(StoreSeed.VALID_STORE_ID)); - - result.Should().BeTrue(); - } - - [Fact] - public virtual async Task ReturnsFalse_GivenStoreByIdSpecWithInvalidStore() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.AnyAsync(new StoreByIdSpec(0)); - - result.Should().BeFalse(); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AsAsyncEnumerable.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AsAsyncEnumerable.cs deleted file mode 100644 index e22b4330..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_AsAsyncEnumerable.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("ReadCollection")] -public class RepositoryOfT_AsAsyncEnumerable : RepositoryOfT_AnyAsync_TestKit -{ - public RepositoryOfT_AsAsyncEnumerable(DatabaseFixture fixture) - : base(fixture, SpecificationEvaluator.Default) - { - } -} - -[Collection("ReadCollection")] -public class RepositoryOfT_AsAsyncEnumerable_Cached : RepositoryOfT_AnyAsync_TestKit -{ - public RepositoryOfT_AsAsyncEnumerable_Cached(DatabaseFixture fixture) - : base(fixture, SpecificationEvaluator.Cached) - { - } -} - -public abstract class RepositoryOfT_AsAsyncEnumerable_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_AsAsyncEnumerable_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task ReturnsTrueOnStoresRecords_WithoutSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var results = repo.AsAsyncEnumerable(new StoreIncludeProductsSpec()); - - await foreach (var result in results.WithCancellation(CancellationToken.None)) - { - result.Should().NotBeNull(); - result.Products.Should().NotBeEmpty(); - } - } - - [Fact] - public virtual async Task ReturnsStoreWithIdFrom15To30_GivenStoresByIdAsAsyncEnumerableSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var ids = Enumerable.Range(15, 16); - var spec = new StoresByIdListSpec(ids); - - var counter = 0; - var results = repo.AsAsyncEnumerable(spec); - await foreach (var result in results.WithCancellation(CancellationToken.None)) - { - result.Should().NotBeNull(); - result.Products.Should().NotBeEmpty(); - ++counter; - } - - counter.Should().Be(16); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs deleted file mode 100644 index bfc37391..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_DeleteRangeAsync.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("WriteCollection")] -public class RepositoryOfT_DeleteRangeAsync : RepositoryOfT_DeleteRangeAsync_TestKit -{ - public RepositoryOfT_DeleteRangeAsync(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Default) - { - } -} - -public abstract class RepositoryOfT_DeleteRangeAsync_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_DeleteRangeAsync_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task DeletesProductWithStoreIdOne_GivenProductByStoreIdSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - await repo.DeleteRangeAsync(new ProductByStoreIdSpec(1)); - - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.StoreId == 1); - } - - [Fact] - public virtual async Task DeletesProductWithIdOne_GivenProductByIdSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - await repo.DeleteRangeAsync(new ProductByIdSpec(2)); - - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 2); - } - - [Fact] - public virtual async Task DeletesProductWithIdOne_GivenProductByIdAsUntrackedWithIdentityResolutionSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - await repo.DeleteRangeAsync(new ProductByIdAsUntrackedWithIdentityResolutionSpec(3)); - - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 3); - } - - [Fact] - public virtual async Task DeletesProductWithIdOne_GivenProductByIdAsTrackedSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - await repo.DeleteRangeAsync(new ProductByIdAsTrackedSpec(4)); - - var products = await repo.ListAsync(); - products.Should().NotBeNullOrEmpty(); - products.Should().NotContain(e => e.Id == 4); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetById.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetById.cs deleted file mode 100644 index bdd390c1..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetById.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("ReadCollection")] -public class RepositoryOfT_GetById : RepositoryOfT_GetById_TestKit -{ - public RepositoryOfT_GetById(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Default) - { - } -} - -[Collection("ReadCollection")] -public class RepositoryOfT_GetById_Cached : RepositoryOfT_GetById_TestKit -{ - public RepositoryOfT_GetById_Cached(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Cached) - { - } -} - -public abstract class RepositoryOfT_GetById_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_GetById_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task ReturnsStore_GivenId() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetByIdAsync(StoreSeed.VALID_STORE_ID); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - } - - [Fact] - public virtual async Task ReturnsStore_GivenGenericId() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetByIdAsync(StoreSeed.VALID_STORE_ID); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetBySpec.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetBySpec.cs deleted file mode 100644 index 8ec6a514..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_GetBySpec.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("ReadCollection")] -public class RepositoryOfT_GetBySpec : RepositoryOfT_GetBySpec_TestKit -{ - public RepositoryOfT_GetBySpec(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Default) - { - } -} - -[Collection("ReadCollection")] -public class RepositoryOfT_GetBySpec_Cached : RepositoryOfT_GetBySpec_TestKit -{ - public RepositoryOfT_GetBySpec_Cached(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Cached) - { - } -} - -public abstract class RepositoryOfT_GetBySpec_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_GetBySpec_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task ReturnsStoreWithProducts_GivenStoreByIdIncludeProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new StoreByIdIncludeProductsSpec(StoreSeed.VALID_STORE_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - result.Products.Count.Should().BeGreaterThan(1); - } - - [Fact] - public virtual async Task ReturnsStoreWithAddress_GivenStoreByIdIncludeAddressSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new StoreByIdIncludeAddressSpec(StoreSeed.VALID_STORE_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - result.Address?.Street.Should().Be(AddressSeed.VALID_STREET_FOR_STOREID1); - } - - [Fact] - public virtual async Task ReturnsStoreWithAddressAndProduct_GivenStoreByIdIncludeAddressAndProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new StoreByIdIncludeAddressAndProductsSpec(StoreSeed.VALID_STORE_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - result.Products.Count.Should().BeGreaterThan(1); - result.Address?.Street.Should().Be(AddressSeed.VALID_STREET_FOR_STOREID1); - } - - [Fact] - public virtual async Task ReturnsStoreWithProducts_GivenStoreByIdIncludeProductsUsingStringSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new StoreByIdIncludeProductsUsingStringSpec(StoreSeed.VALID_STORE_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - result.Products.Count.Should().BeGreaterThan(1); - } - - [Fact] - public virtual async Task ReturnsCompanyWithStoresAndAddress_GivenCompanyByIdIncludeStoresThenIncludeAddressSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new CompanyByIdIncludeStoresThenIncludeAddressSpec(CompanySeed.VALID_COMPANY_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); - result.Stores.Count.Should().BeGreaterThan(49); - result.Stores.Select(x => x.Address).Count().Should().BeGreaterThan(0); - } - - [Fact] - public virtual async Task ReturnsCompanyWithStoresAndProducts_GivenCompanyByIdIncludeStoresThenIncludeProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new CompanyByIdIncludeStoresThenIncludeProductsSpec(CompanySeed.VALID_COMPANY_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); - result.Stores.Count.Should().BeGreaterThan(49); - result.Stores.Select(x => x.Products).Count().Should().BeGreaterThan(1); - } - - [Fact] - public virtual async Task ReturnsUntrackedCompany_GivenCompanyByIdAsUntrackedSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - dbContext.ChangeTracker.Clear(); - - var result = await repo.GetBySpecAsync(new CompanyByIdAsUntrackedSpec(CompanySeed.VALID_COMPANY_ID)); - - result.Should().NotBeNull(); - result?.Name.Should().Be(CompanySeed.VALID_COMPANY_NAME); - dbContext.Entry(result!).State.Should().Be(Microsoft.EntityFrameworkCore.EntityState.Detached); - } - - [Fact] - public virtual async Task ReturnsStoreWithCompanyAndCountryAndStoresForCompany_GivenStoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.GetBySpecAsync(new StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec(StoreSeed.VALID_STORE_ID)); - - result.Should().NotBeNull(); - result!.Name.Should().Be(StoreSeed.VALID_STORE_NAME); - result.Company.Should().NotBeNull(); - result.Company!.Country.Should().NotBeNull(); - result.Company!.Stores.Should().HaveCountGreaterOrEqualTo(2); - result.Company?.Stores?.Should().Match(x => x.Any(z => z.Products.Count > 0)); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_ListAsync.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_ListAsync.cs deleted file mode 100644 index e2649c9e..00000000 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/RepositoryOfT_ListAsync.cs +++ /dev/null @@ -1,263 +0,0 @@ -using Ardalis.Specification.EntityFrameworkCore.IntegrationTests.Fixture; -using Ardalis.Specification.UnitTests.Fixture.Entities; -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using Ardalis.Specification.UnitTests.Fixture.Specs; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace Ardalis.Specification.EntityFrameworkCore.IntegrationTests; - -[Collection("ReadCollection")] -public class RepositoryOfT_ListAsync : RepositoryOfT_ListAsync_TestKit -{ - public RepositoryOfT_ListAsync(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Default) - { - } -} - -[Collection("ReadCollection")] -public class RepositoryOfT_ListAsync_Cached : RepositoryOfT_ListAsync_TestKit -{ - public RepositoryOfT_ListAsync_Cached(DatabaseFixture fixture) : base(fixture, SpecificationEvaluator.Cached) - { - } -} - -public abstract class RepositoryOfT_ListAsync_TestKit -{ - private readonly DbContextOptions _dbContextOptions; - private readonly ISpecificationEvaluator _specificationEvaluator; - - protected RepositoryOfT_ListAsync_TestKit(DatabaseFixture fixture, ISpecificationEvaluator specificationEvaluator) - { - _dbContextOptions = fixture.DbContextOptions; - _specificationEvaluator = specificationEvaluator; - } - - [Fact] - public virtual async Task ReturnsStoreWithProducts_GivenStoreIncludeProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new StoreIncludeProductsSpec()); - - result.Should().NotBeNull(); - result.Should().NotBeEmpty(); - result[0].Products.Should().NotBeEmpty(); - } - - [Fact] - public virtual async Task ReturnsStoreWithAddress_GivenStoreIncludeAddressSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new StoreIncludeAddressSpec()); - - result.Should().NotBeNull(); - result.Should().NotBeEmpty(); - result[0].Address.Should().NotBeNull(); - } - - [Fact] - public virtual async Task ReturnsStoreWithAddressAndProduct_GivenStoreIncludeAddressAndProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new StoreIncludeAddressAndProductsSpec()); - - result.Should().NotBeNull(); - result.Should().NotBeEmpty(); - result[0].Address.Should().NotBeNull(); - result[0].Products.Should().NotBeEmpty(); - } - - [Fact] - public virtual async Task ReturnsCompanyWithStoreWithIdOne_GivenCompanyIncludeFilteredStoresSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new CompanyIncludeFilteredStoresSpec(1)); - - result.Should().NotBeNull(); - result.Should().NotBeEmpty(); - result[0].Stores.Should().NotBeEmpty(); - result[0].Stores.Should().HaveCount(1); - result[0].Stores.First().Id.Should().Be(1); - } - - [Fact] - public virtual async Task ReturnsStoreWithIdFrom15To30_GivenStoresByIdListSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var ids = Enumerable.Range(15, 16); - var spec = new StoresByIdListSpec(ids); - - var stores = await repo.ListAsync(spec); - - stores.Count.Should().Be(16); - stores.OrderBy(x => x.Id).First().Id.Should().Be(15); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(30); - } - - [Fact] - public virtual async Task ReturnsSecondPageOfStoreNames_GivenStoreNamesPaginatedSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoreNamesPaginatedSpec(skip, take); - - var storeNames = await repo.ListAsync(spec); - - storeNames.Count.Should().Be(take); - storeNames.First().Should().Be("Store 11"); - storeNames.Last().Should().Be("Store 20"); - } - - [Fact] - public virtual async Task ReturnsSecondPageOfStores_GivenStoresPaginatedSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresPaginatedSpec(skip, take); - - var stores = await repo.ListAsync(spec); - - stores.Count.Should().Be(take); - stores.OrderBy(x => x.Id).First().Id.Should().Be(11); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(20); - } - - [Fact] - public virtual async Task ReturnsOrderStoresByNameDescForCompanyWithId2_GivenStoresByCompanyOrderedDescByNameSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var spec = new StoresByCompanyOrderedDescByNameSpec(2); - - var stores = await repo.ListAsync(spec); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_LAST_ID); - } - - [Fact] - public virtual async Task ReturnsOrderStoresByNameDescThenByIdForCompanyWithId2_GivenStoresByCompanyOrderedDescByNameThenByIdSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var spec = new StoresByCompanyOrderedDescByNameThenByIdSpec(2); - - var stores = await repo.ListAsync(spec); - - stores.First().Id.Should().Be(99); - stores.Last().Id.Should().Be(98); - } - - [Fact] - public virtual async Task ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompanyPaginatedOrderedDescByNameSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresByCompanyPaginatedOrderedDescByNameSpec(2, skip, take); - - var stores = await repo.ListAsync(spec); - - stores.Count.Should().Be(take); - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_PAGE2_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_PAGE2_LAST_ID); - } - - [Fact] - public virtual async Task ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompanyPaginatedSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresByCompanyPaginatedSpec(2, skip, take); - - var stores = await repo.ListAsync(spec); - - stores.Count.Should().Be(take); - stores.OrderBy(x => x.Id).First().Id.Should().Be(61); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(70); - } - - [Fact] - public virtual async Task ReturnsOrderedStores_GivenStoresOrderedSpecByName() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var spec = new StoresOrderedSpecByName(); - - var stores = await repo.ListAsync(spec); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_LAST_ID); - } - - [Fact] - public virtual async Task ReturnsOrderedStores_GivenStoresOrderedDescendingByNameSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var spec = new StoresOrderedDescendingByNameSpec(); - - var stores = await repo.ListAsync(spec); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_LAST_ID); - } - - [Fact] - public virtual async Task ReturnsStoreContainingCity1_GivenStoreIncludeProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new StoreSearchByNameOrCitySpec(StoreSeed.VALID_Search_City_Key)); - - result.Should().NotBeNull(); - result.Should().ContainSingle(); - result[0].Id.Should().Be(StoreSeed.VALID_Search_ID); - result[0].City.Should().Contain(StoreSeed.VALID_Search_City_Key); - } - - [Fact] - public virtual async Task ReturnsAllProducts_GivenStoreSelectManyProductsSpec() - { - using var dbContext = new TestDbContext(_dbContextOptions); - var repo = new Repository(dbContext, _specificationEvaluator); - - var result = await repo.ListAsync(new StoreProductNamesSpec()); - - result.Should().NotBeNull(); - result.Should().HaveCount(ProductSeed.TOTAL_PRODUCT_COUNT); - result.OrderBy(x => x).First().Should().Be(ProductSeed.VALID_PRODUCT_NAME); - } -} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests.csproj b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Ardalis.Specification.EntityFrameworkCore.Tests.csproj similarity index 85% rename from Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests.csproj rename to Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Ardalis.Specification.EntityFrameworkCore.Tests.csproj index 21564e83..8ada58f9 100644 --- a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests/Ardalis.Specification.EntityFrameworkCore.IntegrationTests.csproj +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Ardalis.Specification.EntityFrameworkCore.Tests.csproj @@ -2,8 +2,8 @@ net8.0 - 12.0 - disable + 13.0 + enable enable false @@ -15,6 +15,8 @@ + + all @@ -27,7 +29,7 @@ - + diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingEvaluatorTests.cs new file mode 100644 index 00000000..a461b1a8 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingEvaluatorTests.cs @@ -0,0 +1,25 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class AsNoTrackingEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly AsNoTrackingEvaluator _evaluator = AsNoTrackingEvaluator.Instance; + + [Fact] + public void Applies_GivenAsNoTracking() + { + var spec = new Specification(); + spec.Query.AsNoTracking(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .AsNoTracking() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingWithIdentityResolutionEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingWithIdentityResolutionEvaluatorTests.cs new file mode 100644 index 00000000..f11cb69a --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsNoTrackingWithIdentityResolutionEvaluatorTests.cs @@ -0,0 +1,25 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class AsNoTrackingWithIdentityResolutionEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly AsNoTrackingWithIdentityResolutionEvaluator _evaluator = AsNoTrackingWithIdentityResolutionEvaluator.Instance; + + [Fact] + public void Applies_GivenAsNoTrackingWithIdentityResolution() + { + var spec = new Specification(); + spec.Query.AsNoTrackingWithIdentityResolution(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .AsNoTrackingWithIdentityResolution() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsSplitQueryEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsSplitQueryEvaluatorTests.cs new file mode 100644 index 00000000..dc691d13 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsSplitQueryEvaluatorTests.cs @@ -0,0 +1,41 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class AsSplitQueryEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly AsSplitQueryEvaluator _evaluator = AsSplitQueryEvaluator.Instance; + + [Fact] + public void QueriesMatch_GivenAsSplitQuery() + { + var spec = new Specification(); + spec.Query.AsSplitQuery(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .ToQueryString(); + + var expected = DbContext.Countries + .AsSplitQuery() + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void Applies_GivenAsSplitQuery() + { + var spec = new Specification(); + spec.Query.AsSplitQuery(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .AsSplitQuery() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsTrackingEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsTrackingEvaluatorTests.cs new file mode 100644 index 00000000..92cffe06 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/AsTrackingEvaluatorTests.cs @@ -0,0 +1,25 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class AsTrackingEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly AsTrackingEvaluator _evaluator = AsTrackingEvaluator.Instance; + + [Fact] + public void Applies_GivenAsTracking() + { + var spec = new Specification(); + spec.Query.AsTracking(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .AsTracking() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IgnoreQueryFiltersEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IgnoreQueryFiltersEvaluatorTests.cs new file mode 100644 index 00000000..8f607087 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IgnoreQueryFiltersEvaluatorTests.cs @@ -0,0 +1,41 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class IgnoreQueryFiltersEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly IgnoreQueryFiltersEvaluator _evaluator = IgnoreQueryFiltersEvaluator.Instance; + + [Fact] + public void QueriesMatch_GivenIgnoreQueryFilters() + { + var spec = new Specification(); + spec.Query.IgnoreQueryFilters(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .ToQueryString(); + + var expected = DbContext.Countries + .IgnoreQueryFilters() + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void Applies_GivenIgnoreQueryFilters() + { + var spec = new Specification(); + spec.Query.IgnoreQueryFilters(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .IgnoreQueryFilters() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeEvaluatorTests.cs new file mode 100644 index 00000000..5d9f6749 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeEvaluatorTests.cs @@ -0,0 +1,93 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class IncludeEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly IncludeEvaluator _evaluator = IncludeEvaluator.Default; + + [Fact] + public void QueriesMatch_GivenIncludeExpressions() + { + var spec = new Specification(); + spec.Query + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country); + + var actual = _evaluator + .GetQuery(DbContext.Stores, spec) + .ToQueryString(); + + var expected = DbContext.Stores + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void QueriesMatch_GivenThenIncludeWithVariousNavigationCollectionTypes() + { + var spec = new Specification(); + spec.Query + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.InnerNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.ListNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IEnumerableNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IReadOnlyCollectionNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IReadOnlyListNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.ListNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IEnumerableNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IReadOnlyCollectionNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IReadOnlyListNavigation) + .ThenInclude(x => x.ListNavigation2); + + var actual = _evaluator + .GetQuery(DbContext.Foos, spec) + .ToQueryString(); + + var expected = DbContext.Foos + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.InnerNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.ListNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IEnumerableNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IReadOnlyCollectionNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.OuterNavigation) + .ThenInclude(x => x.IReadOnlyListNavigation) + .ThenInclude(x => x.InnerNavigation2) + .Include(x => x.ListNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IEnumerableNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IReadOnlyCollectionNavigation) + .ThenInclude(x => x.ListNavigation2) + .Include(x => x.IReadOnlyListNavigation) + .ThenInclude(x => x.ListNavigation2) + .ToQueryString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeStringEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeStringEvaluatorTests.cs new file mode 100644 index 00000000..e217c271 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/IncludeStringEvaluatorTests.cs @@ -0,0 +1,45 @@ +//namespace Tests.Evaluators; + +//[Collection("SharedCollection")] +//public class IncludeStringEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +//{ +// private static readonly IncludeStringEvaluator _evaluator = IncludeStringEvaluator.Instance; + +// [Fact] +// public void QueriesMatch_GivenIncludeString() +// { +// var spec = new Specification(); +// spec.Query +// .Include(nameof(Address)); + +// var actual = _evaluator +// .Evaluate(DbContext.Stores, spec) +// .ToQueryString(); + +// var expected = DbContext.Stores +// .Include(nameof(Address)) +// .ToQueryString(); + +// actual.Should().Be(expected); +// } + +// [Fact] +// public void QueriesMatch_GivenMultipleIncludeStrings() +// { +// var spec = new Specification(); +// spec.Query +// .Include(nameof(Address)) +// .Include($"{nameof(Company)}.{nameof(Country)}"); + +// var actual = _evaluator +// .Evaluate(DbContext.Stores, spec) +// .ToQueryString(); + +// var expected = DbContext.Stores +// .Include(nameof(Address)) +// .Include($"{nameof(Company)}.{nameof(Country)}") +// .ToQueryString(); + +// actual.Should().Be(expected); +// } +//} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/OrderEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/OrderEvaluatorTests.cs new file mode 100644 index 00000000..9bdae31f --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/OrderEvaluatorTests.cs @@ -0,0 +1,43 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class OrderEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly OrderEvaluator _evaluator = OrderEvaluator.Instance; + + [Fact] + public void QueriesMatch_GivenOrder() + { + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString(); + + var expected = DbContext.Stores + .OrderBy(x => x.Id) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void QueriesMatch_GivenOrderChain() + { + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id) + .ThenBy(x => x.Name); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString(); + + var expected = DbContext.Stores + .OrderBy(x => x.Id) + .ThenBy(x => x.Name) + .ToQueryString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/ParameterReplacerVisitorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/ParameterReplacerVisitorTests.cs new file mode 100644 index 00000000..bfb1411f --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/ParameterReplacerVisitorTests.cs @@ -0,0 +1,21 @@ +//using System.Linq.Expressions; + +//namespace Tests.Evaluators; + +//public class ParameterReplacerVisitorTests +//{ +// [Fact] +// public void ReturnsExpressionWithReplacedParameter() +// { +// Expression> expected = (y, z) => y == 1; + +// Expression> expression = (x, z) => x == 1; +// var oldParameter = expression.Parameters[0]; +// var newExpression = Expression.Parameter(typeof(int), "y"); + +// var visitor = new ParameterReplacerVisitor(oldParameter, newExpression); +// var result = visitor.Visit(expression); + +// result.ToString().Should().Be(expected.ToString()); +// } +//} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SearchEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SearchEvaluatorTests.cs new file mode 100644 index 00000000..81d987b3 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SearchEvaluatorTests.cs @@ -0,0 +1,75 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class SearchEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly Ardalis.Specification.EntityFrameworkCore.SearchEvaluator _evaluator = Ardalis.Specification.EntityFrameworkCore.SearchEvaluator.Instance; + + [Fact] + public void QueriesMatch_GivenNoSearch() + { + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 0); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString(); + + var expected = DbContext.Stores + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void QueriesMatch_GivenSingleSearch() + { + var storeTerm = "ab1"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 0) + .Search(x => x.Name, $"%{storeTerm}%"); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + var expected = DbContext.Stores + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%")) + .ToQueryString(); + + actual.Should().Be(expected); + } + + // TODO: Fix this case. [fatii, 11/02/2025] + //[Fact] + //public void QueriesMatch_GivenMultipleSearch() + //{ + // var storeTerm = "ab1"; + // var companyTerm = "ab2"; + // var countryTerm = "ab3"; + // var streetTerm = "ab4"; + + // var spec = new Specification(); + // spec.Query + // .Where(x => x.Id > 0) + // .Search(x => x.Name, $"%{storeTerm}%") + // .Search(x => x.Company.Name, $"%{companyTerm}%") + // .Search(x => x.Company.Country.Name, $"%{countryTerm}%", 3) + // .Search(x => x.Address.Street, $"%{streetTerm}%", 2); + + // var actual = _evaluator.GetQuery(DbContext.Stores, spec) + // .ToQueryString() + // .Replace("__criteria_SearchTerm_", "__Format_"); + + // var expected = DbContext.Stores + // .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + // || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + // .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + // .Where(x => EF.Functions.Like(x.Company.Country.Name, $"%{countryTerm}%")) + // .ToQueryString(); + + // actual.Should().Be(expected); + //} +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SpecificationEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SpecificationEvaluatorTests.cs new file mode 100644 index 00000000..31521901 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/SpecificationEvaluatorTests.cs @@ -0,0 +1,316 @@ +using System.Runtime.CompilerServices; + +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class SpecificationEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly SpecificationEvaluator _evaluator = SpecificationEvaluator.Default; + + public record Customer(int Id, string FirstName, string LastName, List? Emails = null); + + [Fact] + public void ThrowsArgumentNullException_GivenNullSpec() + { + var sut = () => _evaluator.GetQuery(DbContext.Countries, (Specification)null!); + + sut.Should().Throw().WithParameterName("specification"); + } + + [Fact] + public void ThrowsArgumentNullException_GivenNullSpecificationWithSelector() + { + var sut = () => _evaluator.GetQuery(DbContext.Countries, (Specification)null!); + + sut.Should().Throw().WithParameterName("specification"); + } + + [Fact] + public void ThrowsSelectorNotFoundException_GivenNoSelector() + { + var spec = new Specification(); + + var sut = () => _evaluator.GetQuery(DbContext.Countries, spec); + + sut.Should().Throw(); + } + + [Fact] + public void GivenEmptySpec() + { + var spec = new Specification(); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString(); + + var expected = DbContext.Stores + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void GivenFullQuery() + { + var id = 2; + var name = "Store1"; + var storeTerm = "ab1"; + var companyTerm = "ab2"; + var streetTerm = "ab3"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Search(x => x.Name, $"%{storeTerm}%") + .Search(x => x.Company.Name, $"%{companyTerm}%") + .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .Skip(1) + .Take(10) + .IgnoreQueryFilters(); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + // The expression in the spec are applied in a predefined order. + var expected = DbContext.Stores + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .IgnoreQueryFilters() + // Pagination always applied in the end + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void GivenExpressionsInRandomOrder() + { + var id = 2; + var name = "Store1"; + var storeTerm = "ab1"; + var companyTerm = "ab2"; + var streetTerm = "ab3"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Search(x => x.Name, $"%{storeTerm}%") + .Search(x => x.Company.Name, $"%{companyTerm}%") + .Where(x => x.Name == name) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + .Skip(1) + .Take(10) + .IgnoreQueryFilters(); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + // The expression in the spec are applied in a predefined order. + var expected = DbContext.Stores + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .IgnoreQueryFilters() + // Pagination always applied in the end + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void GivenFullQueryWithSelect() + { + var id = 2; + var name = "Store1"; + var storeTerm = "ab1"; + var companyTerm = "ab2"; + var streetTerm = "ab3"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Search(x => x.Name, $"%{storeTerm}%") + .Search(x => x.Company.Name, $"%{companyTerm}%") + .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .Skip(1) + .Take(10) + .IgnoreQueryFilters(); + spec.Query.Select(x => x.Name); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + // The expression in the spec are applied in a predefined order. + var expected = DbContext.Stores + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .IgnoreQueryFilters() + .Select(x => x.Name) + // Pagination always applied in the end + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + // TODO: Fix SelectMany query [fatii, 11/02/2025] + //[Fact] + //public void GivenFullQueryWithSelectMany() + //{ + // var id = 2; + // var name = "Store1"; + // var storeTerm = "ab1"; + // var companyTerm = "ab2"; + // var streetTerm = "ab3"; + + // var spec = new Specification(); + // spec.Query + // .Where(x => x.Id > id) + // .Where(x => x.Name == name) + // .Search(x => x.Name, $"%{storeTerm}%") + // .Search(x => x.Company.Name, $"%{companyTerm}%") + // .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + // .Include(nameof(Address)) + // .Include(x => x.Products.Where(x => x.Id > 10)) + // .ThenInclude(x => x.Images) + // .Include(x => x.Company) + // .ThenInclude(x => x.Country) + // .OrderBy(x => x.Id) + // .ThenByDescending(x => x.Name) + // .Skip(1) + // .Take(10) + // .IgnoreQueryFilters(); + // spec.Query.SelectMany(x => x.Products.Select(x => x.Name)); + + // var actual = _evaluator.GetQuery(DbContext.Stores, spec) + // .ToQueryString() + // .Replace("__criteria_SearchTerm_", "__Format_"); + + // // The expression in the spec are applied in a predefined order. + // var expected = DbContext.Stores + // .Where(x => x.Id > id) + // .Where(x => x.Name == name) + // .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + // || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + // .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + // .Include(nameof(Address)) + // .Include(x => x.Products.Where(x => x.Id > 10)) + // .ThenInclude(x => x.Images) + // .Include(x => x.Company) + // .ThenInclude(x => x.Country) + // .OrderBy(x => x.Id) + // .ThenByDescending(x => x.Name) + // .IgnoreQueryFilters() + // .SelectMany(x => x.Products.Select(x => x.Name)) + // // Pagination always applied in the end + // .Skip(1) + // .Take(10) + // .ToQueryString(); + + // actual.Should().Be(expected); + //} + + [Fact] + public void GivenSpecAndIgnorePagination() + { + var id = 2; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Skip(1) + .Take(10); + + var actual = _evaluator.GetQuery(DbContext.Stores, spec, true) + .ToQueryString(); + + var expected = DbContext.Stores + .Where(x => x.Id > id) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void GivenSpecWithMultipleFlags() + { + var spec = new Specification(); + spec.Query + .IgnoreQueryFilters() + .AsNoTracking() + .AsSplitQuery(); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .Expression + .ToString(); + + var expected = DbContext.Countries + .AsNoTracking() + .IgnoreQueryFilters() + .AsSplitQuery() + .Expression + .ToString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/WhereEvaluatorTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/WhereEvaluatorTests.cs new file mode 100644 index 00000000..4e9ded89 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Evaluators/WhereEvaluatorTests.cs @@ -0,0 +1,29 @@ +namespace Tests.Evaluators; + +[Collection("SharedCollection")] +public class WhereEvaluatorTests(TestFactory factory) : IntegrationTest(factory) +{ + private static readonly WhereEvaluator _evaluator = WhereEvaluator.Instance; + + [Fact] + public void QueriesMatch_GivenWhereExpressions() + { + var id = 10; + var name = "Country1"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Where(x => x.Name == name); + + var actual = _evaluator.GetQuery(DbContext.Countries, spec) + .ToQueryString(); + + var expected = DbContext.Countries + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .ToQueryString(); + + actual.Should().Be(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_ToPagedResult.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_ToPagedResult.cs new file mode 100644 index 00000000..d4955925 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_ToPagedResult.cs @@ -0,0 +1,108 @@ +//namespace Tests.Extensions; + +//[Collection("SharedCollection")] +//public class Extensions_ToPagedResult(TestFactory factory) : IntegrationTest(factory) +//{ +// public record CountryDto(int No, string? Name); + +// [Fact] +// public async Task ReturnsPaginatedItems_GivenPagingFilter() +// { +// var expected = new List +// { +// new(4, "b"), +// }; +// await SeedRangeAsync( +// [ +// new() { No = 9, Name = "a" }, +// new() { No = 9, Name = "c" }, +// new() { No = 1, Name = "b" }, +// new() { No = 2, Name = "b" }, +// new() { No = 3, Name = "b" }, +// new() { No = 4, Name = "b" }, +// new() { No = 9, Name = "d" }, +// ]); + +// var filter = new PagingFilter() { Page = 2, PageSize = 3 }; + +// var result = await DbContext.Countries +// .Where(x => x.Name == "b") +// .OrderBy(x => x.No) +// .Select(x => new CountryDto(x.No, x.Name)) +// .ToPagedResultAsync(filter); + +// result.Should().BeOfType>(); +// result.Pagination.Page.Should().Be(filter.Page); +// result.Pagination.PageSize.Should().Be(filter.PageSize); +// result.Data.Should().Equal(expected); +// } + +// [Fact] +// public async Task ReturnsPaginatedItems_GivenPagingFilterAndPaginationSettings() +// { +// var expected = new List +// { +// new(3, "b"), +// new(4, "b"), +// }; +// await SeedRangeAsync( +// [ +// new() { No = 9, Name = "a" }, +// new() { No = 9, Name = "c" }, +// new() { No = 1, Name = "b" }, +// new() { No = 2, Name = "b" }, +// new() { No = 3, Name = "b" }, +// new() { No = 4, Name = "b" }, +// new() { No = 9, Name = "d" }, +// ]); + +// var paginationSettings = new PaginationSettings(2, 2); +// var filter = new PagingFilter() { Page = 2, PageSize = 3 }; + +// var result = await DbContext.Countries +// .Where(x => x.Name == "b") +// .OrderBy(x => x.No) +// .Select(x => new CountryDto(x.No, x.Name)) +// .ToPagedResultAsync(filter, paginationSettings); + +// result.Should().BeOfType>(); +// result.Pagination.Page.Should().Be(filter.Page); +// result.Pagination.PageSize.Should().Be(paginationSettings.DefaultPageSize); +// result.Data.Should().Equal(expected); +// } + +// [Fact] +// public async Task ReturnsPaginatedItemsWithAggregatedTakeSkip_GivenPagingFilterAndTakeSkip() +// { +// var expected = new List +// { +// new(2, "b"), +// new(3, "b"), +// }; +// await SeedRangeAsync( +// [ +// new() { No = 9, Name = "a" }, +// new() { No = 9, Name = "c" }, +// new() { No = 1, Name = "b" }, +// new() { No = 2, Name = "b" }, +// new() { No = 3, Name = "b" }, +// new() { No = 4, Name = "b" }, +// new() { No = 9, Name = "d" }, +// ]); + +// var filter = new PagingFilter() { Page = 2, PageSize = 3 }; + +// var result = await DbContext.Countries +// .Where(x => x.Name == "b") +// .OrderBy(x => x.No) +// .Select(x => new CountryDto(x.No, x.Name)) +// .Skip(1) +// .Take(2) +// .ToPagedResultAsync(filter); + +// result.Should().BeOfType>(); +// result.Pagination.Page.Should().Be(PaginationSettings.Default.DefaultPage); +// result.Pagination.PageSize.Should().Be(filter.PageSize); +// result.Data.Should().Equal(expected); +// } +//} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_WithSpecification.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_WithSpecification.cs new file mode 100644 index 00000000..6787998d --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Extensions/Extensions_WithSpecification.cs @@ -0,0 +1,234 @@ +namespace Tests.Extensions; + +[Collection("SharedCollection")] +public class Extensions_WithSpecification(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + + [Fact] + public void QueriesMatch_GivenFullQuery() + { + var id = 1; + var name = "Store1"; + var storeTerm = "ab1"; + var companyTerm = "ab2"; + var streetTerm = "ab3"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Search(x => x.Name, $"%{storeTerm}%") + .Search(x => x.Company.Name, $"%{companyTerm}%") + .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .Skip(1) + .Take(10) + .IgnoreQueryFilters(); + + var actual = DbContext.Stores + .WithSpecification(spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + // The expression in the spec are applied in a predefined order. + var expected = DbContext.Stores + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .IgnoreQueryFilters() + // Pagination always applied in the end + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void QueriesMatch_GivenFullQueryWithSelect() + { + var id = 1; + var name = "Store1"; + var storeTerm = "ab1"; + var companyTerm = "ab2"; + var streetTerm = "ab3"; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Search(x => x.Name, $"%{storeTerm}%") + .Search(x => x.Company.Name, $"%{companyTerm}%") + .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .Skip(1) + .Take(10) + .IgnoreQueryFilters(); + spec.Query.Select(x => x.Name); + + var actual = DbContext.Stores + .WithSpecification(spec) + .ToQueryString() + .Replace("__criteria_SearchTerm_", "__Format_"); + + // The expression in the spec are applied in a predefined order. + var expected = DbContext.Stores + .Where(x => x.Id > id) + .Where(x => x.Name == name) + .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Id > 10)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name) + .IgnoreQueryFilters() + .Select(x => x.Name) + // Pagination always applied in the end + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + // TODO: Fix SelectMany query [fatii, 11/02/2025] + //[Fact] + //public void QueriesMatch_GivenFullQueryWithSelectMany() + //{ + // var id = 1; + // var name = "Store1"; + // var storeTerm = "ab1"; + // var companyTerm = "ab2"; + // var streetTerm = "ab3"; + + // var spec = new Specification(); + // spec.Query + // .Where(x => x.Id > id) + // .Where(x => x.Name == name) + // .Search(x => x.Name, $"%{storeTerm}%") + // .Search(x => x.Company.Name, $"%{companyTerm}%") + // .Search(x => x.Address.Street, $"%{streetTerm}%", 2) + // .Include(nameof(Address)) + // .Include(x => x.Products.Where(x => x.Id > 10)) + // .ThenInclude(x => x.Images) + // .Include(x => x.Company) + // .ThenInclude(x => x.Country) + // .OrderBy(x => x.Id) + // .ThenByDescending(x => x.Name) + // .Skip(1) + // .Take(10) + // .IgnoreQueryFilters(); + // spec.Query.SelectMany(x => x.Products.Select(x => x.Name)); + + // var actual = DbContext.Stores + // .WithSpecification(spec) + // .ToQueryString() + // .Replace("__criteria_SearchTerm_", "__Format_"); + + // // The expression in the spec are applied in a predefined order. + // var expected = DbContext.Stores + // .Where(x => x.Id > id) + // .Where(x => x.Name == name) + // .Where(x => EF.Functions.Like(x.Name, $"%{storeTerm}%") + // || EF.Functions.Like(x.Company.Name, $"%{companyTerm}%")) + // .Where(x => EF.Functions.Like(x.Address.Street, $"%{streetTerm}%")) + // .Include(nameof(Address)) + // .Include(x => x.Products.Where(x => x.Id > 10)) + // .ThenInclude(x => x.Images) + // .Include(x => x.Company) + // .ThenInclude(x => x.Country) + // .OrderBy(x => x.Id) + // .ThenByDescending(x => x.Name) + // .IgnoreQueryFilters() + // .SelectMany(x => x.Products.Select(x => x.Name)) + // // Pagination always applied in the end + // .Skip(1) + // .Take(10) + // .ToQueryString(); + + // actual.Should().Be(expected); + //} + + [Fact] + public void QueriesMatch_GivenCustomEvaluator() + { + var id = 1; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Skip(1) + .Take(10); + + var actual = DbContext.Stores + .WithSpecification(spec, new MySpecificationEvaluator()) + .ToQueryString(); + + var expected = DbContext.Stores + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + [Fact] + public void QueriesMatch_GivenSelectorAndCustomEvaluator() + { + var id = 1; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > id) + .Skip(1) + .Take(10); + spec.Query.Select(x => new CountryDto(x.Name)); + + var actual = DbContext.Stores + .WithSpecification(spec, new MySpecificationEvaluator()) + .ToQueryString(); + + var expected = DbContext.Stores + .Select(x => new CountryDto(x.Name)) + .Skip(1) + .Take(10) + .ToQueryString(); + + actual.Should().Be(expected); + } + + // It will ignore all where expressions. + public class MySpecificationEvaluator : SpecificationEvaluator + { + public MySpecificationEvaluator() + { + Evaluators.Remove(WhereEvaluator.Instance); + } + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Address.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Address.cs new file mode 100644 index 00000000..7d56bb0b --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Address.cs @@ -0,0 +1,10 @@ +namespace Tests.Fixture; + +public record Address +{ + public int Id { get; set; } + public string? Street { get; set; } + + public int StoreId { get; set; } + public Store Store { get; set; } = default!; +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Company.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Company.cs new file mode 100644 index 00000000..9a80e846 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Company.cs @@ -0,0 +1,12 @@ +namespace Tests.Fixture; + +public record Company +{ + public int Id { get; set; } + public required string Name { get; set; } + + public int CountryId { get; set; } + public Country Country { get; set; } = default!; + + public List Stores { get; set; } = []; +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Country.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Country.cs new file mode 100644 index 00000000..7e38d144 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Country.cs @@ -0,0 +1,9 @@ +namespace Tests.Fixture; + +public record Country +{ + public int Id { get; set; } + public int No { get; set; } + public string? Name { get; set; } + public bool IsDeleted { get; set; } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Foo.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Foo.cs new file mode 100644 index 00000000..9af7e58b --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Foo.cs @@ -0,0 +1,51 @@ +namespace Tests.Fixture; + +public class Foo +{ + public int Id { get; set; } + public string? Dummy { get; set; } + public OuterNavigation OuterNavigation { get; set; } = default!; + + public List ListNavigation => _listNavigation; + private readonly List _listNavigation = []; + public IEnumerable IEnumerableNavigation => _iEnumerableNavigation.AsEnumerable(); + private readonly List _iEnumerableNavigation = []; + + public IReadOnlyCollection IReadOnlyCollectionNavigation => _iReadOnlyCollectionNavigation.AsReadOnly(); + private readonly List _iReadOnlyCollectionNavigation = []; + + public IReadOnlyList IReadOnlyListNavigation => _iReadOnlyListNavigation.AsReadOnly(); + private readonly List _iReadOnlyListNavigation = []; +} + +public class OuterNavigation +{ + public int Id { get; set; } + public string? Dummy { get; set; } + + public InnerNavigation InnerNavigation { get; set; } = default!; + public List ListNavigation => _listNavigation; + private readonly List _listNavigation = []; + public IEnumerable IEnumerableNavigation => _iEnumerableNavigation.AsEnumerable(); + private readonly List _iEnumerableNavigation = []; + + public IReadOnlyCollection IReadOnlyCollectionNavigation => _iReadOnlyCollectionNavigation.AsReadOnly(); + private readonly List _iReadOnlyCollectionNavigation = []; + + public IReadOnlyList IReadOnlyListNavigation => _iReadOnlyListNavigation.AsReadOnly(); + private readonly List _iReadOnlyListNavigation = []; +} + +public class InnerNavigation +{ + public int Id { get; set; } + public string? Dummy { get; set; } + public InnerNavigation2 InnerNavigation2 { get; set; } = default!; + public List ListNavigation2 { get; set; } = []; +} + +public class InnerNavigation2 +{ + public int Id { get; set; } + public string? Dummy { get; set; } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Product.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Product.cs new file mode 100644 index 00000000..e9576a7f --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Product.cs @@ -0,0 +1,12 @@ +namespace Tests.Fixture; + +public record Product +{ + public int Id { get; set; } + public string? Name { get; set; } + + public int StoreId { get; set; } + public Store Store { get; set; } = default!; + + public List? Images { get; set; } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/ProductImage.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/ProductImage.cs new file mode 100644 index 00000000..8511e6d4 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/ProductImage.cs @@ -0,0 +1,9 @@ +namespace Tests.Fixture; + +public record ProductImage +{ + public int Id { get; set; } + public string? ImageUrl { get; set; } + public int ProductId { get; set; } + public Product Product { get; set; } = default!; +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Store.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Store.cs new file mode 100644 index 00000000..49a21a79 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Data/Store.cs @@ -0,0 +1,15 @@ +namespace Tests.Fixture; + +public record Store +{ + public int Id { get; set; } + public string? Name { get; set; } + public string? City { get; set; } + + public int CompanyId { get; set; } + public Company Company { get; set; } = default!; + + public Address Address { get; set; } = default!; + + public List Products { get; set; } = []; +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/IntegrationTest.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/IntegrationTest.cs new file mode 100644 index 00000000..dcf6cf2a --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/IntegrationTest.cs @@ -0,0 +1,39 @@ +namespace Tests.Fixture; + +public class IntegrationTest(TestFactory testFactory) : IAsyncLifetime +{ + protected TestDbContext DbContext { get; private set; } = default!; + + public Task InitializeAsync() + { + DbContext = new TestDbContext(testFactory.DbContextOptions); + return Task.CompletedTask; + } + + public async Task DisposeAsync() + { + await DbContext.DisposeAsync(); + await testFactory.ResetDatabase(); + } + + public async Task SeedAsync(TEntity entity) where TEntity : class + { + using var dbContext = new TestDbContext(testFactory.DbContextOptions); + dbContext.Add(entity); + await dbContext.SaveChangesAsync(); + } + + public async Task SeedRangeAsync(TEntity[] entities) where TEntity : class + { + using var dbContext = new TestDbContext(testFactory.DbContextOptions); + dbContext.AddRange(entities); + await dbContext.SaveChangesAsync(); + } + + public async Task SeedRangeAsync(IEnumerable entities) + { + using var dbContext = new TestDbContext(testFactory.DbContextOptions); + dbContext.AddRange(entities); + await dbContext.SaveChangesAsync(); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Repository.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Repository.cs new file mode 100644 index 00000000..30236437 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/Repository.cs @@ -0,0 +1,5 @@ +namespace Tests.Fixture; + +public class Repository(DbContext context) : RepositoryBase(context) where T : class +{ +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/SharedCollection.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/SharedCollection.cs new file mode 100644 index 00000000..eacc6ef7 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/SharedCollection.cs @@ -0,0 +1,6 @@ +namespace Tests.Fixture; + +[CollectionDefinition("SharedCollection")] +public class SharedCollection : ICollectionFixture +{ +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestDbContext.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestDbContext.cs new file mode 100644 index 00000000..7595188c --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestDbContext.cs @@ -0,0 +1,27 @@ +namespace Tests.Fixture; + +public class TestDbContext(DbContextOptions options) : DbContext(options) +{ + public DbSet Foos => Set(); + public DbSet Countries => Set(); + public DbSet Companies => Set(); + public DbSet Stores => Set(); + public DbSet
Addresses => Set
(); + public DbSet Products => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasOne(x => x.Address) + .WithOne(x => x.Store) + .HasForeignKey
(x => x.StoreId); + + modelBuilder.Entity() + .HasMany() + .WithOne(x => x.Country) + .HasForeignKey(x => x.CountryId); + + modelBuilder.Entity() + .HasQueryFilter(x => !x.IsDeleted); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestFactory.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestFactory.cs new file mode 100644 index 00000000..a5e3e4ce --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Fixture/TestFactory.cs @@ -0,0 +1,76 @@ +using MartinCostello.SqlLocalDb; +using Respawn; +using Testcontainers.MsSql; + +namespace Tests.Fixture; + +public class TestFactory : IAsyncLifetime +{ + // Flag to force using Docker SQL Server. Update it manually if you want to avoid localDb locally. + private const bool _forceDocker = false; + + private string _connectionString = default!; + private Respawner _respawner = default!; + private MsSqlContainer? _dbContainer = null; + + public DbContextOptions DbContextOptions { get; private set; } = default!; + + public Task ResetDatabase() => _respawner.ResetAsync(_connectionString); + + public async Task InitializeAsync() + { + using (var localDB = new SqlLocalDbApi()) + { + if (_forceDocker || !localDB.IsLocalDBInstalled()) + { + _dbContainer = CreateContainer(); + await _dbContainer.StartAsync(); + _connectionString = _dbContainer.GetConnectionString(); + } + else + { + _connectionString = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpecificationEFCoreTestsDB;Integrated Security=SSPI;TrustServerCertificate=True;"; + } + } + + Console.WriteLine($"Connection string: {_connectionString}"); + + DbContextOptions = new DbContextOptionsBuilder() + .UseSqlServer(_connectionString) + .EnableDetailedErrors() + .EnableSensitiveDataLogging() + .Options; + + using var dbContext = new TestDbContext(DbContextOptions); + + //await dbContext.Database.EnsureDeletedAsync(); + await dbContext.Database.EnsureCreatedAsync(); + + _respawner = await Respawner.CreateAsync(_connectionString, new RespawnerOptions + { + DbAdapter = DbAdapter.SqlServer, + SchemasToInclude = ["dbo"], + }); + + await ResetDatabase(); + } + + public async Task DisposeAsync() + { + if (_dbContainer is not null) + { + await _dbContainer.StopAsync(); + } + else + { + //using var dbContext = new TestDbContext(DbContextOptions); + //await dbContext.Database.EnsureDeletedAsync(); + } + } + + private static MsSqlContainer CreateContainer() => new MsSqlBuilder() + .WithImage("mcr.microsoft.com/mssql/server:2022-latest") + .WithName("SpecificationEFCoreTestsDB") + .WithPassword("P@ssW0rd!") + .Build(); +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/GlobalUsings.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/GlobalUsings.cs new file mode 100644 index 00000000..5749e2d1 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/GlobalUsings.cs @@ -0,0 +1,6 @@ +global using FluentAssertions; +global using Microsoft.EntityFrameworkCore; +global using Ardalis.Specification; +global using Ardalis.Specification.EntityFrameworkCore; +global using Tests.Fixture; +global using Xunit; diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/QueryTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/QueryTests.cs new file mode 100644 index 00000000..b1acf145 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/QueryTests.cs @@ -0,0 +1,213 @@ +namespace Tests; + +[Collection("SharedCollection")] +public class QueryTests(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + public record ProductImageDto(string? ImageUrl); + + [Fact] + public async Task ComplexQuery() + { + var validCountryName = "CountryX"; + var validStoreName = "StoreX"; + var validProductName = "ProductX"; + var validProductImageUrl = "ImageUrlX"; + var validCity = "CityX"; + var validCompanyName = "CompanyX"; + var validStreet = "StreetX"; + + var validCityTerm = "ityX"; + var validCompanyTerm = "ompanyX"; + var validStreetTerm = "treetX"; + + var validCountry = new Country { Name = validCountryName, IsDeleted = true }; + var validCompany = new Company { Name = validCompanyName, Country = validCountry }; + var validAddress = new Address { Street = validStreet }; + var invalidCompany = new Company { Name = "Fails", Country = validCountry }; + var invalidAddress = new Address { Street = "Fails" }; + + List GetProducts() => + [ + new() { Name = validProductName, Images = [new() { ImageUrl = validProductImageUrl }] }, + new() { Name = validProductName, Images = null }, + new() { Name = "Fails", Images = [new() { ImageUrl = "Fails" }] }, + ]; + + // The second item is expected based on descending city order. + var stores = new List + { + new() // this passes, city-company same SEARCH group + { + Name = validStoreName, + City = validCity, + Company = invalidCompany, + Address = validAddress with { }, + Products = GetProducts() + }, + new() // this passes, city-company same SEARCH group + { + Name = validStoreName, + City = "WWW", + Company = validCompany, + Address = validAddress with { }, + Products = GetProducts() + }, + new() // fails, city and company + { + Name = validStoreName, + City = "Fails", + Company = invalidCompany, + Address = validAddress with { }, + Products = GetProducts() + }, + new() // fails, address + { + Name = validStoreName, + City = validCity, + Company = validCompany, + Address = invalidAddress with { }, + Products = GetProducts() + }, + new() // fails name + { + Name = "Fails", + City = validCity, + Company = validCompany, + Address = validAddress with { }, + Products = GetProducts() + }, + new() // this passes + { + Name = validStoreName, + City = validCity, + Company = validCompany, + Address = validAddress with { }, + Products = GetProducts() + }, + }; + + await SeedRangeAsync(stores); + + var spec = new Specification(); + spec.Query + .Where(x => x.Name == validStoreName) + .Search(x => x.City, $"%{validCityTerm}%") + .Search(x => x.Company.Name, $"%{validCompanyTerm}%") + .Search(x => x.Address.Street, $"%{validStreetTerm}%", 2) + .Include(nameof(Address)) + .Include(x => x.Products.Where(x => x.Name == validProductName)) + .ThenInclude(x => x.Images) + .Include(x => x.Company) + .ThenInclude(x => x.Country) + .OrderBy(x => x.Id) + .ThenByDescending(x => x.City) + .Skip(1) + .Take(1) + .IgnoreQueryFilters(); + + var result = await DbContext.Stores + .WithSpecification(spec) + .ToListAsync(); + + result.Should().ContainSingle(); + result[0].Name.Should().Be(validStoreName); + result[0].City.Should().Be("WWW"); + result[0].Address.Street.Should().Be(validStreet); + result[0].Company.Name.Should().Be(validCompanyName); + result[0].Company.Country.Name.Should().Be(validCountryName); + result[0].Products.Should().HaveCount(2); + result[0].Products[0].Name.Should().Be(validProductName); + result[0].Products[0].Images.Should().HaveCount(1); + result[0].Products[0].Images![0].ImageUrl.Should().Be(validProductImageUrl); + result[0].Products[1].Name.Should().Be(validProductName); + result[0].Products[1].Images.Should().BeEmpty(); + } + + [Fact] + public async Task QueryWithSelect() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await DbContext.Countries + .WithSpecification(spec) + .ToListAsync(); + + result.Should().HaveSameCount(expected); + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task QueryWithSelectMany() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + var store = new Store + { + Name = "Store1", + Company = new Company + { + Name = "Company1", + Country = new Country { Name = "b" } + }, + }; + var products = new List() + { + new() + { + Store = store, + Images = + [ + new() { ImageUrl = "a" }, + new() { ImageUrl = null }, + new() { ImageUrl = "b" }, + new() { ImageUrl = "b" }, + new() { ImageUrl = "b" }, + new() { ImageUrl = "d" }, + ] + }, + new() + { + Store = store, + Images = null + } + }; + await SeedRangeAsync(products); + + var spec = new Specification(); + spec.Query + .SelectMany(x => x.Images! + .Where(x => x.ImageUrl == "b") + .Select(x => new ProductImageDto(x.ImageUrl))); + + var result = await DbContext.Products + .WithSpecification(spec) + .ToListAsync(); + + result.Should().HaveSameCount(expected); + result.Should().BeEquivalentTo(expected); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/RepositoryTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/RepositoryTests.cs new file mode 100644 index 00000000..9ecc4014 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/RepositoryTests.cs @@ -0,0 +1,89 @@ +//using System.Runtime.CompilerServices; + +//namespace Tests.Repositories; + +//[Collection("SharedCollection")] +//public class RepositoryTests(TestFactory factory) : IntegrationTest(factory) +//{ +// [Fact] +// public void Constructor_SetsDbContext() +// { +// var repo = new Repository(DbContext); + +// Accessors.DbContextOf(repo).Should().BeSameAs(DbContext); +// Accessors.SpecificationEvaluatorOf(repo).Should().BeSameAs(SpecificationEvaluator.Default); +// Accessors.PaginationSettingsOf(repo).Should().BeSameAs(PaginationSettings.Default); +// } + +// [Fact] +// public void Constructor_SetsDbContextAndEvaluator() +// { +// var evaluator = new SpecificationEvaluator(); +// var repo = new Repository(DbContext, evaluator); + +// Accessors.DbContextOf(repo).Should().BeSameAs(DbContext); +// Accessors.SpecificationEvaluatorOf(repo).Should().BeSameAs(evaluator); +// Accessors.PaginationSettingsOf(repo).Should().BeSameAs(PaginationSettings.Default); +// } + +// [Fact] +// public void Constructor_SetsDbContextAndPaginationSettings() +// { +// var paginationSettings = new PaginationSettings(20, 200); +// var repo = new Repository(DbContext, paginationSettings); + +// Accessors.DbContextOf(repo).Should().BeSameAs(DbContext); +// Accessors.SpecificationEvaluatorOf(repo).Should().BeSameAs(SpecificationEvaluator.Default); +// Accessors.PaginationSettingsOf(repo).Should().BeSameAs(paginationSettings); +// } + +// [Fact] +// public void Constructor_SetsDbContextAndEvaluatorAndPaginationSettings() +// { +// var evaluator = new SpecificationEvaluator(); +// var paginationSettings = new PaginationSettings(20, 200); +// var repo = new Repository(DbContext, evaluator, paginationSettings); + +// Accessors.DbContextOf(repo).Should().BeSameAs(DbContext); +// Accessors.SpecificationEvaluatorOf(repo).Should().BeSameAs(evaluator); +// Accessors.PaginationSettingsOf(repo).Should().BeSameAs(paginationSettings); +// } + +// public class Repository : RepositoryWithMapper where T : class +// { +// public Repository(DbContext context) +// : base(context) +// { +// } + +// public Repository(DbContext dbContext, SpecificationEvaluator specificationEvaluator) +// : base(dbContext, specificationEvaluator) +// { +// } + +// public Repository(DbContext dbContext, PaginationSettings paginationSettings) +// : base(dbContext, paginationSettings) +// { +// } + +// public Repository(DbContext dbContext, SpecificationEvaluator specificationEvaluator, PaginationSettings paginationSettings) +// : base(dbContext, specificationEvaluator, paginationSettings) +// { +// } + +// protected override IQueryable Map(IQueryable source) +// => throw new NotImplementedException(); +// } + +// private class Accessors where T : class +// { +// [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_dbContext")] +// public static extern ref DbContext DbContextOf(RepositoryBase @this); + +// [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_evaluator")] +// public static extern ref SpecificationEvaluator SpecificationEvaluatorOf(RepositoryBase @this); + +// [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_paginationSettings")] +// public static extern ref PaginationSettings PaginationSettingsOf(RepositoryWithMapper @this); +// } +//} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_AnyTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_AnyTests.cs new file mode 100644 index 00000000..f716b5fb --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_AnyTests.cs @@ -0,0 +1,181 @@ +namespace Tests.Repositories; + +[Collection("SharedCollection")] +public class Repository_AnyTests(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + + [Fact] + public async Task AnyAsync_ReturnsFalse_GivenNoItems() + { + var repo = new Repository(DbContext); + + var result = await repo.AnyAsync(); + + result.Should().BeFalse(); + } + + [Fact] + public async Task AnyAsync_ReturnsTrue_GivenItems() + { + var expected = new List + { + new() { Name = "a" }, + new() { Name = "b" }, + new() { Name = "c" }, + }; + await SeedRangeAsync(expected); + + var repo = new Repository(DbContext); + + var result = await repo.AnyAsync(); + + result.Should().BeTrue(); + } + + [Fact] + public async Task AnyAsync_ReturnsTrue_GivenSpec() + { + var expected = new List + { + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + + var result = await repo.AnyAsync(spec); + + result.Should().BeTrue(); + } + + [Fact] + public async Task AnyAsync_ReturnsFalse_GivenSpecAndNoMatch() + { + await SeedRangeAsync(new List + { + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "d" }, + }); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + + var result = await repo.AnyAsync(spec); + + result.Should().BeFalse(); + } + + [Fact] + public async Task AnyAsync_ReturnsTrue_GivenProjectionSpec() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.AnyAsync(spec); + + result.Should().BeTrue(); + } + + [Fact] + public async Task AnyAsync_IgnoresPagination_GivenSpecWithPagination() + { + var expected = new List + { + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b") + .Skip(3) + .Take(1); + + var result = await repo.AnyAsync(spec); + + result.Should().BeTrue(); + + // Ensure that the spec's pagination is not altered. + spec.Skip.Should().Be(3); + spec.Take.Should().Be(1); + } + + [Fact] + public async Task AnyAsync_IgnoresPagination_GivenProjectionSpecWithPagination() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b") + .Skip(3) + .Take(1); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.AnyAsync(spec); + + result.Should().BeTrue(); + + // Ensure that the spec's pagination is not altered. + spec.Skip.Should().Be(3); + spec.Take.Should().Be(1); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_CountTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_CountTests.cs new file mode 100644 index 00000000..bc0ef739 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_CountTests.cs @@ -0,0 +1,181 @@ +namespace Tests.Repositories; + +[Collection("SharedCollection")] +public class Repository_CountTests(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + + [Fact] + public async Task CountAsync_ReturnsZero_GivenNoItems() + { + var repo = new Repository(DbContext); + + var result = await repo.CountAsync(); + + result.Should().Be(0); + } + + [Fact] + public async Task CountAsync_ReturnsAllItemsCount() + { + var expected = new List + { + new() { Name = "a" }, + new() { Name = "b" }, + new() { Name = "c" }, + }; + await SeedRangeAsync(expected); + + var repo = new Repository(DbContext); + + var result = await repo.CountAsync(); + + result.Should().Be(expected.Count); + } + + [Fact] + public async Task CountAsync_ReturnsFilteredItemCount_GivenSpec() + { + var expected = new List + { + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + + var result = await repo.CountAsync(spec); + + result.Should().Be(expected.Count); + } + + [Fact] + public async Task CountAsync_ReturnsZero_GivenSpecAndNoMatch() + { + await SeedRangeAsync(new List + { + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "d" }, + }); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + + var result = await repo.CountAsync(spec); + + result.Should().Be(0); + } + + [Fact] + public async Task CountAsync_ReturnsFilteredItemsCount_GivenProjectionSpec() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.CountAsync(spec); + + result.Should().Be(expected.Count); + } + + [Fact] + public async Task CountAsync_IgnoresPagination_GivenSpecWithPagination() + { + var expected = new List + { + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b") + .Skip(1) + .Take(1); + + var result = await repo.CountAsync(spec); + + result.Should().Be(expected.Count); + + // Ensure that the spec's pagination is not altered. + spec.Skip.Should().Be(1); + spec.Take.Should().Be(1); + } + + [Fact] + public async Task CountAsync_IgnoresPagination_GivenProjectionSpecWithPagination() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b") + .Skip(1) + .Take(1); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.CountAsync(spec); + + result.Should().Be(expected.Count); + + // Ensure that the spec's pagination is not altered. + spec.Skip.Should().Be(1); + spec.Take.Should().Be(1); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_FirstTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_FirstTests.cs new file mode 100644 index 00000000..b7969444 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_FirstTests.cs @@ -0,0 +1,253 @@ +namespace Tests.Repositories; + +[Collection("SharedCollection")] +public class Repository_FirstTests(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + + [Fact] + public async Task FirstOrDefaultAsync_ReturnsFirstItem_GivenEntityExists() + { + var expected = new Country { Name = "b" }; + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + expected, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == expected.Name); + + var result = await repo.FirstOrDefaultAsync(spec); + + result.Should().NotBeNull(); + result!.Name.Should().Be(expected.Name); + } + + [Fact] + public async Task FirstOrDefaultAsync_ReturnsNull_GivenEntityNotExists() + { + var expected = new Country { Name = "b" }; + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == expected.Name); + + var result = await repo.FirstOrDefaultAsync(spec); + + result.Should().BeNull(); + } + + [Fact] + public async Task FirstOrDefaultAsync_ReturnsFirstItem_GivenProjectionAndEntityExists() + { + var expected = new CountryDto("b"); + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + new Country { Name = expected.Name }, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == expected.Name); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.FirstOrDefaultAsync(spec); + + result.Should().NotBeNull(); + result.Should().Be(expected); + } + + [Fact] + public async Task FirstOrDefaultAsync_ReturnsNull_GivenProjectionAndEntityNotExists() + { + var expected = new CountryDto("b"); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == expected.Name); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.FirstOrDefaultAsync(spec); + + result.Should().BeNull(); + } + + [Fact] + public async Task SingleOrDefaultAsync_ReturnsFirstItem_GivenEntityExists() + { + var expected = new Country { Name = "b" }; + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + expected, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + + var result = await repo.SingleOrDefaultAsync(spec); + + result.Should().NotBeNull(); + result!.Name.Should().Be(expected.Name); + } + + [Fact] + public async Task SingleOrDefaultAsync_ReturnsNull_GivenEntityNotExists() + { + var expected = new Country { Name = "b" }; + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + + var result = await repo.SingleOrDefaultAsync(spec); + + result.Should().BeNull(); + } + + [Fact] + public async Task SingleOrDefaultAsync_ThrowsException_GivenMultipleEntitiesExist() + { + var expected = new Country { Name = "b" }; + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + new Country { Name = expected.Name }, + new Country { Name = expected.Name }, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + + var result = () => repo.SingleOrDefaultAsync(spec); + + await result.Should().ThrowAsync(); + } + + [Fact] + public async Task SingleOrDefaultAsync_ReturnsFirstItem_GivenProjectionAndEntityExists() + { + var expected = new CountryDto("b"); + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + new Country { Name = expected.Name }, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.SingleOrDefaultAsync(spec); + + result.Should().NotBeNull(); + result.Should().Be(expected); + } + + [Fact] + public async Task SingleOrDefaultAsync_ReturnsNull_GivenProjectionAndEntityNotExists() + { + var expected = new CountryDto("b"); + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.SingleOrDefaultAsync(spec); + + result.Should().BeNull(); + } + + [Fact] + public async Task SingleOrDefaultAsync_ThrowsException_GivenProjectionMultipleEntitiesExist() + { + var expected = new CountryDto("b"); + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + new Country { Name = expected.Name }, + new Country { Name = expected.Name }, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + var spec = new SingleResultSpecification(); + spec.Query + .Where(x => x.Name == expected.Name); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = () => repo.SingleOrDefaultAsync(spec); + + await result.Should().ThrowAsync(); + } + + [Fact] + public async Task FindAsync_ReturnsFirstItem_GivenIdExists() + { + var expected = new Country { Name = "b" }; + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + expected, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + + var result = await repo.GetByIdAsync(expected.Id); + + result.Should().NotBeNull(); + result!.Name.Should().Be(expected.Name); + } + + [Fact] + public async Task FindAsync_ReturnsFromChangeTracker_GivenItemIsLoaded() + { + var expected = new Country { Name = "b" }; + await SeedRangeAsync(new[] + { + new Country { Name = "a" }, + expected, + new Country { Name = "c" }, + }); + + var repo = new Repository(DbContext); + + var countryInTracker = await DbContext.Countries.FirstAsync(x => x.Id == expected.Id); + var result = await repo.GetByIdAsync(expected.Id); + + result.Should().NotBeNull(); + result.Should().BeSameAs(countryInTracker); + } + + [Fact] + public async Task FindAsync_ReturnsNull_GivenIdNotExists() + { + var repo = new Repository(DbContext); + + var result = await repo.GetByIdAsync(99); + + result.Should().BeNull(); + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_ListTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_ListTests.cs new file mode 100644 index 00000000..78791ad0 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_ListTests.cs @@ -0,0 +1,115 @@ +namespace Tests.Repositories; + +[Collection("SharedCollection")] +public class Repository_ListTests(TestFactory factory) : IntegrationTest(factory) +{ + public record CountryDto(string? Name); + + [Fact] + public async Task ListAsync_ReturnsAllItems() + { + var expected = new List + { + new() { Name = "a" }, + new() { Name = "b" }, + new() { Name = "c" }, + }; + await SeedRangeAsync(expected); + + var repo = new Repository(DbContext); + + var result = await repo.ListAsync(); + + result.Should().HaveSameCount(expected); + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task ListAsync_ReturnsFilteredItems_GivenSpec() + { + var expected = new List + { + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + + var result = await repo.ListAsync(spec); + + result.Should().HaveSameCount(expected); + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task ListAsync_ReturnsFilteredItems_GivenProjectionSpec() + { + var expected = new List + { + new("b"), + new("b"), + new("b"), + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "b" }, + new() { Name = "d" }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Where(x => x.Name == "b"); + spec.Query.Select(x => new CountryDto(x.Name)); + + var result = await repo.ListAsync(spec); + + result.Should().HaveSameCount(expected); + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task AsAsyncEnumerable_ReturnsFilteredItems_GivenSpec() + { + var expected = new List + { + new() { Name = "b1" }, + new() { Name = "b2" }, + new() { Name = "b3" }, + }; + await SeedRangeAsync( + [ + new() { Name = "a" }, + new() { Name = "c" }, + .. expected, + new() { Name = null }, + ]); + + var repo = new Repository(DbContext); + var spec = new Specification(); + spec.Query + .Search(x => x.Name, "b%") + .OrderBy(x => x.Name); + + var suffix = 1; + await foreach (var item in repo.AsAsyncEnumerable(spec)) + { + item.Name.Should().Be($"b{suffix++}"); + } + } +} diff --git a/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_WriteTests.cs b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_WriteTests.cs new file mode 100644 index 00000000..348f25e2 --- /dev/null +++ b/Specification.EntityFrameworkCore/tests/Ardalis.Specification.EntityFrameworkCore.Tests/Repositories/Repository_WriteTests.cs @@ -0,0 +1,100 @@ +namespace Tests.Repositories; + +[Collection("SharedCollection")] +public class Repository_WriteTests(TestFactory factory) : IntegrationTest(factory) +{ + [Fact] + public async Task AddAsync_ShouldAddEntity() + { + var repo = new Repository(DbContext); + var country = new Country + { + Name = Guid.NewGuid().ToString(), + }; + + await repo.AddAsync(country); + DbContext.ChangeTracker.Clear(); + + var countriesInDb = await DbContext.Countries.IgnoreQueryFilters().ToListAsync(); + countriesInDb.Should().ContainSingle(); + countriesInDb.First().Name.Should().Be(country.Name); + } + + [Fact] + public async Task AddAsync_ShouldAddMultipleEntities() + { + var repo = new Repository(DbContext); + var countries = new[] + { + new Country { Name = Guid.NewGuid().ToString() }, + new Country { Name = Guid.NewGuid().ToString() }, + new Country { Name = Guid.NewGuid().ToString() }, + }; + + await repo.AddRangeAsync(countries); + DbContext.ChangeTracker.Clear(); + + var countriesInDb = await DbContext.Countries.ToListAsync(); + countriesInDb.Should().HaveCount(3); + countriesInDb.Select(x => x.Name).Should().BeEquivalentTo(countries.Select(x => x.Name)); + } + + [Fact] + public async Task UpdateAsync_ShouldUpdateEntity() + { + var repo = new Repository(DbContext); + var country = new Country + { + Name = Guid.NewGuid().ToString(), + }; + await SeedAsync(country); + + country = await DbContext.Countries.FirstAsync(); + country.Name = Guid.NewGuid().ToString(); + await repo.UpdateAsync(country); + DbContext.ChangeTracker.Clear(); + + var countriesInDb = await DbContext.Countries.ToListAsync(); + countriesInDb.Should().NotBeNull(); + countriesInDb.Should().ContainSingle(); + countriesInDb.First().Name.Should().Be(country.Name); + } + + [Fact] + public async Task DeleteAsync_ShouldDeleteEntity() + { + var repo = new Repository(DbContext); + var country = new Country + { + Name = Guid.NewGuid().ToString(), + }; + await SeedAsync(country); + + var countryInDb = await DbContext.Countries.FirstAsync(); + await repo.DeleteAsync(countryInDb); + DbContext.ChangeTracker.Clear(); + + var countriesInDb = await DbContext.Countries.ToListAsync(); + countriesInDb.Should().BeEmpty(); + } + + [Fact] + public async Task DeleteAsync_ShouldDeleteMultipleEntities() + { + var repo = new Repository(DbContext); + var countries = new[] + { + new Country { Name = Guid.NewGuid().ToString() }, + new Country { Name = Guid.NewGuid().ToString() }, + new Country { Name = Guid.NewGuid().ToString() }, + }; + await SeedRangeAsync(countries); + + var countriesInDb = await DbContext.Countries.ToListAsync(); + await repo.DeleteRangeAsync(countriesInDb); + DbContext.ChangeTracker.Clear(); + + countriesInDb = await DbContext.Countries.ToListAsync(); + countriesInDb.Should().BeEmpty(); + } +} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Ardalis.Specification.UnitTests.csproj b/Specification/tests/Ardalis.Specification.Tests/Ardalis.Specification.Tests.csproj similarity index 83% rename from Specification/tests/Ardalis.Specification.UnitTests/Ardalis.Specification.UnitTests.csproj rename to Specification/tests/Ardalis.Specification.Tests/Ardalis.Specification.Tests.csproj index 98f013c5..6e1284fd 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/Ardalis.Specification.UnitTests.csproj +++ b/Specification/tests/Ardalis.Specification.Tests/Ardalis.Specification.Tests.csproj @@ -2,7 +2,7 @@ net8.0;net472 - 12.0 + 13.0 enable false @@ -10,6 +10,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTracking.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTracking.cs new file mode 100644 index 00000000..36e6ab01 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTracking.cs @@ -0,0 +1,69 @@ +namespace Tests.Builders; + +public class Builder_AsNoTracking +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoAsNoTracking() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.AsNoTracking.Should().Be(false); + spec2.AsNoTracking.Should().Be(false); + } + + [Fact] + public void DoesNothing_GivenAsNoTrackingWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTracking(false); + + var spec2 = new Specification(); + spec2.Query + .AsNoTracking(false); + + spec1.AsNoTracking.Should().Be(false); + spec2.AsNoTracking.Should().Be(false); + } + + [Fact] + public void SetsAsNoTracking_GivenAsNoTracking() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTracking(); + + var spec2 = new Specification(); + spec2.Query + .AsNoTracking(); + + spec1.AsNoTracking.Should().Be(true); + spec2.AsNoTracking.Should().Be(true); + } + + [Fact] + public void SetsAsNoTracking_GivenOtherTrackingBehavior() + { + var spec1 = new Specification(); + spec1.Query + .AsTracking() + .AsNoTrackingWithIdentityResolution() + .AsNoTracking(); + + var spec2 = new Specification(); + spec2.Query + .AsTracking() + .AsNoTrackingWithIdentityResolution() + .AsNoTracking(); + + spec1.AsTracking.Should().Be(false); + spec1.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec1.AsNoTracking.Should().Be(true); + spec2.AsTracking.Should().Be(false); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec2.AsNoTracking.Should().Be(true); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTrackingWithIdentityResolution.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTrackingWithIdentityResolution.cs new file mode 100644 index 00000000..c54fce32 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsNoTrackingWithIdentityResolution.cs @@ -0,0 +1,69 @@ +namespace Tests.Builders; + +public class Builder_AsNoTrackingWithIdentityResolution +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoAsNoTrackingWithIdentityResolution() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(false); + } + + [Fact] + public void DoesNothing_GivenAsNoTrackingWithIdentityResolutionWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTrackingWithIdentityResolution(false); + + var spec2 = new Specification(); + spec2.Query + .AsNoTrackingWithIdentityResolution(false); + + spec1.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(false); + } + + [Fact] + public void SetsAsNoTrackingWithIdentityResolution_GivenAsNoTrackingWithIdentityResolution() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTrackingWithIdentityResolution(); + + var spec2 = new Specification(); + spec2.Query + .AsNoTrackingWithIdentityResolution(); + + spec1.AsNoTrackingWithIdentityResolution.Should().Be(true); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(true); + } + + [Fact] + public void SetsAsNoTrackingWithIdentityResolution_GivenOtherTrackingBehavior() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTracking() + .AsTracking() + .AsNoTrackingWithIdentityResolution(); + + var spec2 = new Specification(); + spec2.Query + .AsNoTracking() + .AsTracking() + .AsNoTrackingWithIdentityResolution(); + + spec1.AsNoTracking.Should().Be(false); + spec1.AsTracking.Should().Be(false); + spec1.AsNoTrackingWithIdentityResolution.Should().Be(true); + spec2.AsNoTracking.Should().Be(false); + spec2.AsTracking.Should().Be(false); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(true); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsSplitQuery.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsSplitQuery.cs new file mode 100644 index 00000000..a3a996eb --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsSplitQuery.cs @@ -0,0 +1,46 @@ +namespace Tests.Builders; + +public class Builder_AsSplitQuery +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoAsSplitQuery() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.AsSplitQuery.Should().Be(false); + spec2.AsSplitQuery.Should().Be(false); + } + + [Fact] + public void DoesNothing_GivenAsSplitQueryWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .AsSplitQuery(false); + + var spec2 = new Specification(); + spec2.Query + .AsSplitQuery(false); + + spec1.AsSplitQuery.Should().Be(false); + spec2.AsSplitQuery.Should().Be(false); + } + + [Fact] + public void SetsAsSplitQuery_GivenAsSplitQuery() + { + var spec1 = new Specification(); + spec1.Query + .AsSplitQuery(); + + var spec2 = new Specification(); + spec2.Query + .AsSplitQuery(); + + spec1.AsSplitQuery.Should().Be(true); + spec2.AsSplitQuery.Should().Be(true); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsTracking.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsTracking.cs new file mode 100644 index 00000000..25f0dc75 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_AsTracking.cs @@ -0,0 +1,69 @@ +namespace Tests.Builders; + +public class Builder_AsTracking +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoAsTracking() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.AsTracking.Should().Be(false); + spec2.AsTracking.Should().Be(false); + } + + [Fact] + public void DoesNothing_GivenAsTrackingWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .AsTracking(false); + + var spec2 = new Specification(); + spec2.Query + .AsTracking(false); + + spec1.AsTracking.Should().Be(false); + spec2.AsTracking.Should().Be(false); + } + + [Fact] + public void SetsAsNoTracking_GivenAsTracking() + { + var spec1 = new Specification(); + spec1.Query + .AsTracking(); + + var spec2 = new Specification(); + spec2.Query + .AsTracking(); + + spec1.AsTracking.Should().Be(true); + spec2.AsTracking.Should().Be(true); + } + + [Fact] + public void SetsAsTracking_GivenOtherTrackingBehavior() + { + var spec1 = new Specification(); + spec1.Query + .AsNoTracking() + .AsNoTrackingWithIdentityResolution() + .AsTracking(); + + var spec2 = new Specification(); + spec2.Query + .AsNoTracking() + .AsNoTrackingWithIdentityResolution() + .AsTracking(); + + spec1.AsNoTracking.Should().Be(false); + spec1.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec1.AsTracking.Should().Be(true); + spec2.AsNoTracking.Should().Be(false); + spec2.AsNoTrackingWithIdentityResolution.Should().Be(false); + spec2.AsTracking.Should().Be(true); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IgnoreQueryFilters.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IgnoreQueryFilters.cs new file mode 100644 index 00000000..63d1ffc2 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IgnoreQueryFilters.cs @@ -0,0 +1,46 @@ +namespace Tests.Builders; + +public class Builder_IgnoreQueryFilters +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoIgnoreQueryFilters() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.IgnoreQueryFilters.Should().Be(false); + spec2.IgnoreQueryFilters.Should().Be(false); + } + + [Fact] + public void DoesNothing_GivenIgnoreQueryFiltersWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .IgnoreQueryFilters(false); + + var spec2 = new Specification(); + spec2.Query + .IgnoreQueryFilters(false); + + spec1.IgnoreQueryFilters.Should().Be(false); + spec2.IgnoreQueryFilters.Should().Be(false); + } + + [Fact] + public void SetsIgnoreQueryFilters_GivenIgnoreQueryFilters() + { + var spec1 = new Specification(); + spec1.Query + .IgnoreQueryFilters(); + + var spec2 = new Specification(); + spec2.Query + .IgnoreQueryFilters(); + + spec1.IgnoreQueryFilters.Should().Be(true); + spec2.IgnoreQueryFilters.Should().Be(true); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Include.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Include.cs new file mode 100644 index 00000000..381e1f1b --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Include.cs @@ -0,0 +1,73 @@ +namespace Tests.Builders; + +public class Builder_Include +{ + public record Customer(int Id, Address Address, Contact Contact); + public record Address(int Id, string City); + public record Contact(int Id, string Email); + + [Fact] + public void DoesNothing_GivenNoInclude() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.IncludeExpressions.Should().BeEmpty(); + spec2.IncludeExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenIncludeWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address, false); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address, false); + + spec1.IncludeExpressions.Should().BeEmpty(); + spec2.IncludeExpressions.Should().BeEmpty(); + } + + [Fact] + public void AddsInclude_GivenInclude() + { + Expression> expr = x => x.Address; + + var spec1 = new Specification(); + spec1.Query + .Include(expr); + + var spec2 = new Specification(); + spec2.Query + .Include(expr); + + spec1.IncludeExpressions.Should().ContainSingle(); + spec1.IncludeExpressions.First().LambdaExpression.Should().BeSameAs(expr); + spec1.IncludeExpressions.First().Type.Should().Be(IncludeTypeEnum.Include); + spec2.IncludeExpressions.Should().ContainSingle(); + spec2.IncludeExpressions.First().LambdaExpression.Should().BeSameAs(expr); + spec2.IncludeExpressions.First().Type.Should().Be(IncludeTypeEnum.Include); + } + + [Fact] + public void AddsInclude_GivenMultipleInclude() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address) + .Include(x => x.Contact); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address) + .Include(x => x.Contact); + + spec1.IncludeExpressions.Should().HaveCount(2); + spec1.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + spec2.IncludeExpressions.Should().HaveCount(2); + spec2.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IncludeString.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IncludeString.cs new file mode 100644 index 00000000..355c91c4 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_IncludeString.cs @@ -0,0 +1,68 @@ +namespace Tests.Builders; + +public class Builder_IncludeString +{ + public record Customer(int Id, Address Address, Contact Contact); + public record Address(int Id, string City); + public record Contact(int Id, string Email); + + [Fact] + public void DoesNothing_GivenNoIncludeString() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.IncludeStrings.Should().BeEmpty(); + spec2.IncludeStrings.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenIncludeStringWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .Include(nameof(Address), false); + + var spec2 = new Specification(); + spec2.Query + .Include(nameof(Address), false); + + spec1.IncludeStrings.Should().BeEmpty(); + spec2.IncludeStrings.Should().BeEmpty(); + } + + [Fact] + public void AddsIncludeString_GivenIncludeString() + { + var includeString = nameof(Address); + var spec1 = new Specification(); + spec1.Query + .Include(includeString); + + var spec2 = new Specification(); + spec2.Query + .Include(includeString); + + spec1.IncludeStrings.Should().ContainSingle(); + spec1.IncludeStrings.First().Should().BeSameAs(includeString); + spec2.IncludeStrings.Should().ContainSingle(); + spec2.IncludeStrings.First().Should().BeSameAs(includeString); + } + + [Fact] + public void AddsIncludeString_GivenMultipleIncludeString() + { + var spec1 = new Specification(); + spec1.Query + .Include(nameof(Address)) + .Include(nameof(Contact)); + + var spec2 = new Specification(); + spec2.Query + .Include(nameof(Address)) + .Include(nameof(Contact)); + + spec1.IncludeStrings.Should().HaveCount(2); + spec2.IncludeStrings.Should().HaveCount(2); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderBy.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderBy.cs new file mode 100644 index 00000000..942658ac --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderBy.cs @@ -0,0 +1,70 @@ +namespace Tests.Builders; + +public class Builder_OrderBy +{ + public record Customer(int Id, string FirstName, string LastName); + + [Fact] + public void DoesNothing_GivenNoOrderBy() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenOrderByWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName, false); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName, false); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void AddsOrderBy_GivenOrderBy() + { + Expression> expr = x => x.FirstName; + var spec1 = new Specification(); + spec1.Query + .OrderBy(expr); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(expr); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.First().KeySelector.Should().BeSameAs(expr); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.First().KeySelector.Should().BeSameAs(expr); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + } + + [Fact] + public void AddsOrderBy_GivenMultipleOrderBy() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .OrderBy(x => x.LastName); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .OrderBy(x => x.LastName); + + spec1.OrderExpressions.Should().HaveCount(2); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + spec2.OrderExpressions.Should().HaveCount(2); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderByDescending.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderByDescending.cs new file mode 100644 index 00000000..ca15d621 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderByDescending.cs @@ -0,0 +1,70 @@ +namespace Tests.Builders; + +public class Builder_OrderByDescending +{ + public record Customer(int Id, string FirstName, string LastName); + + [Fact] + public void DoesNothing_GivenNoOrderByDescending() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenOrderByDescendingWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .OrderByDescending(x => x.FirstName, false); + + var spec2 = new Specification(); + spec2.Query + .OrderByDescending(x => x.FirstName, false); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void AddsOrderByDescending_GivenOrderByDescending() + { + Expression> expr = x => x.FirstName; + var spec1 = new Specification(); + spec1.Query + .OrderByDescending(expr); + + var spec2 = new Specification(); + spec2.Query + .OrderByDescending(expr); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.First().KeySelector.Should().BeSameAs(expr); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderByDescending); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.First().KeySelector.Should().BeSameAs(expr); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderByDescending); + } + + [Fact] + public void AddsOrderByDescending_GivenMultipleOrderByDescending() + { + var spec1 = new Specification(); + spec1.Query + .OrderByDescending(x => x.FirstName) + .OrderByDescending(x => x.LastName); + + var spec2 = new Specification(); + spec2.Query + .OrderByDescending(x => x.FirstName) + .OrderByDescending(x => x.LastName); + + spec1.OrderExpressions.Should().HaveCount(2); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderByDescending)); + spec2.OrderExpressions.Should().HaveCount(2); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderByDescending)); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenBy.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenBy.cs new file mode 100644 index 00000000..fe63113d --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenBy.cs @@ -0,0 +1,136 @@ +namespace Tests.Builders; + +public class Builder_OrderThenBy +{ + public record Customer(int Id, string FirstName, string LastName, string Email); + + [Fact] + public void DoesNothing_GivenThenByWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName, false); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName, false); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + } + + [Fact] + public void DoesNothing_GivenThenByWithDiscardedTopChain() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName, false) + .ThenBy(x => x.LastName); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName, false) + .ThenBy(x => x.LastName); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenThenByWithDiscardedNestedChain() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName, false) + .ThenBy(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName, false) + .ThenBy(x => x.Email); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + } + + [Fact] + public void AddsThenBy_GivenThenBy() + { + Expression> expr = x => x.LastName; + + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenBy(expr); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenBy(expr); + + spec1.OrderExpressions.Should().HaveCount(2); + spec1.OrderExpressions.Last().KeySelector.Should().BeSameAs(expr); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenBy); + spec2.OrderExpressions.Should().HaveCount(2); + spec2.OrderExpressions.Last().KeySelector.Should().BeSameAs(expr); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenBy); + } + + [Fact] + public void AddsThenBy_GivenMultipleThenBy() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName) + .ThenBy(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName) + .ThenBy(x => x.Email); + + spec1.OrderExpressions.Should().HaveCount(3); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Skip(1).Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.ThenBy)); + spec2.OrderExpressions.Should().HaveCount(3); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Skip(1).Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.ThenBy)); + } + + [Fact] + public void AddsThenBy_GivenThenByThenByDescending() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName) + .ThenByDescending(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenBy(x => x.LastName) + .ThenByDescending(x => x.Email); + + spec1.OrderExpressions.Should().HaveCount(3); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.ThenBy); + spec1.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + spec2.OrderExpressions.Should().HaveCount(3); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.ThenBy); + spec2.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenByDescending.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenByDescending.cs new file mode 100644 index 00000000..b5a7f17a --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_OrderThenByDescending.cs @@ -0,0 +1,136 @@ +namespace Tests.Builders; + +public class Builder_OrderThenByDescending +{ + public record Customer(int Id, string FirstName, string LastName, string Email); + + [Fact] + public void DoesNothing_GivenThenByDescendingWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName, false); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName, false); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + } + + [Fact] + public void DoesNothing_GivenThenByDescendingWithDiscardedTopChain() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName, false) + .ThenByDescending(x => x.LastName); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName, false) + .ThenByDescending(x => x.LastName); + + spec1.OrderExpressions.Should().BeEmpty(); + spec2.OrderExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenThenByDescendingWithDiscardedNestedChain() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName, false) + .ThenByDescending(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName, false) + .ThenByDescending(x => x.Email); + + spec1.OrderExpressions.Should().ContainSingle(); + spec1.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + spec2.OrderExpressions.Should().ContainSingle(); + spec2.OrderExpressions.Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.OrderBy)); + } + + [Fact] + public void AddsThenByDescending_GivenThenByDescending() + { + Expression> expr = x => x.LastName; + + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(expr); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(expr); + + spec1.OrderExpressions.Should().HaveCount(2); + spec1.OrderExpressions.Last().KeySelector.Should().BeSameAs(expr); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + spec2.OrderExpressions.Should().HaveCount(2); + spec2.OrderExpressions.Last().KeySelector.Should().BeSameAs(expr); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + } + + [Fact] + public void AddsThenByDescending_GivenMultipleThenByDescending() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName) + .ThenByDescending(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName) + .ThenByDescending(x => x.Email); + + spec1.OrderExpressions.Should().HaveCount(3); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Skip(1).Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.ThenByDescending)); + spec2.OrderExpressions.Should().HaveCount(3); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Skip(1).Should().AllSatisfy(x => x.OrderType.Should().Be(OrderTypeEnum.ThenByDescending)); + } + + [Fact] + public void AddsThenBy_GivenThenByDescendingThenBy() + { + var spec1 = new Specification(); + spec1.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName) + .ThenBy(x => x.Email); + + var spec2 = new Specification(); + spec2.Query + .OrderBy(x => x.FirstName) + .ThenByDescending(x => x.LastName) + .ThenBy(x => x.Email); + + spec1.OrderExpressions.Should().HaveCount(3); + spec1.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec1.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + spec1.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenBy); + spec2.OrderExpressions.Should().HaveCount(3); + spec2.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); + spec2.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.ThenByDescending); + spec2.OrderExpressions.Last().OrderType.Should().Be(OrderTypeEnum.ThenBy); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Search.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Search.cs new file mode 100644 index 00000000..af84587a --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Search.cs @@ -0,0 +1,93 @@ +namespace Tests.Builders; + +public class Builder_Search +{ + public record Customer(int Id, string FirstName, string LastName); + + [Fact] + public void DoesNothing_GivenNoSearch() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.SearchCriterias.Should().BeEmpty(); + spec2.SearchCriterias.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenSearchWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .Search(x => x.FirstName, "%a%", false); + + var spec2 = new Specification(); + spec2.Query + .Search(x => x.FirstName, "%a%", false); + + spec1.SearchCriterias.Should().BeEmpty(); + spec2.SearchCriterias.Should().BeEmpty(); + } + + [Fact] + public void AddsSearch_GivenSingleSearch() + { + Expression> expr = x => x.FirstName; + var pattern = "%a%"; + + var spec1 = new Specification(); + spec1.Query + .Search(expr, pattern); + + var spec2 = new Specification(); + spec2.Query + .Search(expr, pattern); + + spec1.SearchCriterias.Should().ContainSingle(); + spec1.SearchCriterias.First().Selector.Should().BeSameAs(expr); + spec1.SearchCriterias.First().SearchTerm.Should().Be(pattern); + spec1.SearchCriterias.First().SearchGroup.Should().Be(1); + spec2.SearchCriterias.Should().ContainSingle(); + spec2.SearchCriterias.First().Selector.Should().BeSameAs(expr); + spec2.SearchCriterias.First().SearchTerm.Should().Be(pattern); + spec2.SearchCriterias.First().SearchGroup.Should().Be(1); + } + + [Fact] + public void AddsSearch_GivenMultipleSearchInSameGroup() + { + var spec1 = new Specification(); + spec1.Query + .Search(x => x.FirstName, "%a%") + .Search(x => x.LastName, "%a%"); + + var spec2 = new Specification(); + spec2.Query + .Search(x => x.FirstName, "%a%") + .Search(x => x.LastName, "%a%"); + + spec1.SearchCriterias.Should().HaveCount(2); + spec1.SearchCriterias.Should().AllSatisfy(x => x.SearchGroup.Should().Be(1)); + spec2.SearchCriterias.Should().HaveCount(2); + spec2.SearchCriterias.Should().AllSatisfy(x => x.SearchGroup.Should().Be(1)); + } + + [Fact] + public void AddsSearch_GivenMultipleSearchInDifferentGroups() + { + var spec1 = new Specification(); + spec1.Query + .Search(x => x.FirstName, "%a%", 1) + .Search(x => x.LastName, "%a%", 2); + + var spec2 = new Specification(); + spec2.Query + .Search(x => x.FirstName, "%a%", 1) + .Search(x => x.LastName, "%a%", 2); + + spec1.SearchCriterias.Should().HaveCount(2); + spec1.SearchCriterias.Should().OnlyHaveUniqueItems(x => x.SearchGroup); + spec2.SearchCriterias.Should().HaveCount(2); + spec2.SearchCriterias.Should().OnlyHaveUniqueItems(x => x.SearchGroup); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Select.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Select.cs new file mode 100644 index 00000000..69dbc4ba --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Select.cs @@ -0,0 +1,42 @@ +namespace Tests.Builders; + +public class Builder_Select +{ + public record Customer(int Id, string FirstName, string LastName); + + [Fact] + public void DoesNothing_GivenNoSelect() + { + var spec = new Specification(); + + spec.Selector.Should().BeNull(); + } + + [Fact] + public void AddsSelector_GivenSelect() + { + Expression> expr = x => x.FirstName; + + var spec = new Specification(); + spec.Query + .Select(expr); + + spec.Selector.Should().NotBeNull(); + spec.Selector.Should().BeSameAs(expr); + } + + [Fact] + public void OverwritesSelector_GivenMultipleSelect() + { + Expression> expr = x => x.FirstName; + + var spec = new Specification(); + spec.Query + .Select(x => x.LastName); + spec.Query + .Select(expr); + + spec.Selector.Should().NotBeNull(); + spec.Selector.Should().BeSameAs(expr); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_SelectMany.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_SelectMany.cs new file mode 100644 index 00000000..9960841e --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_SelectMany.cs @@ -0,0 +1,42 @@ +namespace Tests.Builders; + +public class Builder_SelectMany +{ + public record Customer(int Id, List FirstName, List LastName); + + [Fact] + public void DoesNothing_GivenNoSelectMany() + { + var spec = new Specification(); + + spec.SelectorMany.Should().BeNull(); + } + + [Fact] + public void AddsSelectorMany_GivenSelectMany() + { + Expression>> expr = x => x.FirstName; + + var spec = new Specification(); + spec.Query + .SelectMany(expr); + + spec.SelectorMany.Should().NotBeNull(); + spec.SelectorMany.Should().BeSameAs(expr); + } + + [Fact] + public void OverwritesSelectorMany_GivenMultipleSelectMany() + { + Expression>> expr = x => x.FirstName; + + var spec = new Specification(); + spec.Query + .SelectMany(x => x.LastName); + spec.Query + .SelectMany(expr); + + spec.SelectorMany.Should().NotBeNull(); + spec.SelectorMany.Should().BeSameAs(expr); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Skip.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Skip.cs new file mode 100644 index 00000000..c179b94a --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Skip.cs @@ -0,0 +1,70 @@ +namespace Tests.Builders; + +public class Builder_Skip +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoSkip() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.Skip.Should().BeNull(); + spec2.Skip.Should().BeNull(); + } + + [Fact] + public void DoesNothing_GivenSkipWithFalseCondition() + { + var skip = 1; + + var spec1 = new Specification(); + spec1.Query + .Skip(skip, false); + + var spec2 = new Specification(); + spec2.Query + .Skip(skip, false); + + spec1.Skip.Should().BeNull(); + spec2.Skip.Should().BeNull(); + } + + [Fact] + public void SetsSkip_GivenSkip() + { + var skip = 1; + + var spec1 = new Specification(); + spec1.Query + .Skip(skip); + + var spec2 = new Specification(); + spec2.Query + .Skip(skip); + + spec1.Skip.Should().Be(skip); + spec2.Skip.Should().Be(skip); + } + + [Fact] + public void ThrowsDuplicateSkipException_GivenNewSkip() + { + var skip = 1; + var skipNew = 2; + + var spec1 = new Specification(); + var sut1 = () => spec1.Query + .Skip(skip) + .Skip(skipNew); + + var spec2 = new Specification(); + var sut2 = () => spec2.Query + .Skip(skip) + .Skip(skipNew); + + sut1.Should().Throw(); + sut2.Should().Throw(); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Take.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Take.cs new file mode 100644 index 00000000..84aa1033 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Take.cs @@ -0,0 +1,70 @@ +namespace Tests.Builders; + +public class Builder_Take +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoTake() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.Take.Should().BeNull(); + spec2.Take.Should().BeNull(); + } + + [Fact] + public void DoesNothing_GivenTakeWithFalseCondition() + { + var take = 1; + + var spec1 = new Specification(); + spec1.Query + .Take(take, false); + + var spec2 = new Specification(); + spec2.Query + .Take(take, false); + + spec1.Take.Should().BeNull(); + spec2.Take.Should().BeNull(); + } + + [Fact] + public void SetsTake_GivenTake() + { + var take = 1; + + var spec1 = new Specification(); + spec1.Query + .Take(take); + + var spec2 = new Specification(); + spec2.Query + .Take(take); + + spec1.Take.Should().Be(take); + spec2.Take.Should().Be(take); + } + + [Fact] + public void ThrowsDuplicateTakeException_GivenNewTake() + { + var take = 1; + var takeNew = 2; + + var spec1 = new Specification(); + var sut1 = () => spec1.Query + .Take(take) + .Take(takeNew); + + var spec2 = new Specification(); + var sut2 = () => spec2.Query + .Take(take) + .Take(takeNew); + + sut1.Should().Throw(); + sut2.Should().Throw(); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_ThenInclude.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_ThenInclude.cs new file mode 100644 index 00000000..d4751b57 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_ThenInclude.cs @@ -0,0 +1,182 @@ +namespace Tests.Builders; + +public class Builder_ThenInclude +{ + public record Customer(int Id, Address Address, List
Addresses); + public record Address(int Id, Contact Contact, List Contacts); + public record Contact(int Id, Phone Phone, List Phones); + public record Phone(int Id, string Number); + + [Fact] + public void DoesNothing_GivenIncludeThenWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact, false) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts, false) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact, false) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts, false); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact, false) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts, false) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact, false) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts, false); + + spec1.IncludeExpressions.Should().HaveCount(4); + spec1.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + spec2.IncludeExpressions.Should().HaveCount(4); + spec2.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + } + + [Fact] + public void DoesNothing_GivenIncludeThenWithDiscardedTopChain() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address, false) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Address, false) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses, false) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses, false) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address, false) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Address, false) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses, false) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses, false) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone); + + spec1.IncludeExpressions.Should().BeEmpty(); + spec2.IncludeExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenIncludeThenWithDiscardedNestedChain() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts, false) + .ThenInclude(x => x.Phone); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact, false) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts, false) + .ThenInclude(x => x.Phone); + + spec1.IncludeExpressions.Should().HaveCount(4); + spec1.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + spec2.IncludeExpressions.Should().HaveCount(4); + spec2.IncludeExpressions.Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + } + + [Fact] + public void AddsIncludeThen_GivenIncludeThen() + { + Expression> expr = x => x.Contact; + + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address) + .ThenInclude(expr); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address) + .ThenInclude(expr); + + spec1.IncludeExpressions.Should().HaveCount(2); + spec1.IncludeExpressions.Last().LambdaExpression.Should().BeSameAs(expr); + spec1.IncludeExpressions.First().Type.Should().Be(IncludeTypeEnum.Include); + spec1.IncludeExpressions.Last().Type.Should().Be(IncludeTypeEnum.ThenInclude); + spec2.IncludeExpressions.Should().HaveCount(2); + spec2.IncludeExpressions.Last().LambdaExpression.Should().BeSameAs(expr); + spec2.IncludeExpressions.First().Type.Should().Be(IncludeTypeEnum.Include); + spec2.IncludeExpressions.Last().Type.Should().Be(IncludeTypeEnum.ThenInclude); + } + + [Fact] + public void AddsIncludeThen_GivenMultipleIncludeThen() + { + var spec1 = new Specification(); + spec1.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone); + + var spec2 = new Specification(); + spec2.Query + .Include(x => x.Address) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Address) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contact) + .ThenInclude(x => x.Phone) + .Include(x => x.Addresses) + .ThenInclude(x => x.Contacts) + .ThenInclude(x => x.Phone); + + spec1.IncludeExpressions.Should().HaveCount(12); + spec1.IncludeExpressions.OrderBy(x => x.Type).Take(4).Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + spec1.IncludeExpressions.OrderBy(x => x.Type).Skip(4).Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.ThenInclude)); + spec2.IncludeExpressions.Should().HaveCount(12); + spec2.IncludeExpressions.OrderBy(x => x.Type).Take(4).Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.Include)); + spec2.IncludeExpressions.OrderBy(x => x.Type).Skip(4).Should().AllSatisfy(x => x.Type.Should().Be(IncludeTypeEnum.ThenInclude)); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Where.cs b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Where.cs new file mode 100644 index 00000000..d0838a55 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Builders/Builder_Where.cs @@ -0,0 +1,66 @@ +namespace Tests.Builders; + +public class Builder_Where +{ + public record Customer(int Id, string Name); + + [Fact] + public void DoesNothing_GivenNoWhere() + { + var spec1 = new Specification(); + var spec2 = new Specification(); + + spec1.WhereExpressions.Should().BeEmpty(); + spec2.WhereExpressions.Should().BeEmpty(); + } + + [Fact] + public void DoesNothing_GivenWhereWithFalseCondition() + { + var spec1 = new Specification(); + spec1.Query + .Where(x => x.Id > 1, false); + + var spec2 = new Specification(); + spec2.Query + .Where(x => x.Id > 1, false); + + spec1.WhereExpressions.Should().BeEmpty(); + spec2.WhereExpressions.Should().BeEmpty(); + } + + [Fact] + public void AddsWhere_GivenWhere() + { + Expression> expr = x => x.Id > 1; + var spec1 = new Specification(); + spec1.Query + .Where(expr); + + var spec2 = new Specification(); + spec2.Query + .Where(expr); + + spec1.WhereExpressions.Should().ContainSingle(); + spec1.WhereExpressions.First().Filter.Should().BeSameAs(expr); + spec2.WhereExpressions.Should().ContainSingle(); + spec2.WhereExpressions.First().Filter.Should().BeSameAs(expr); + } + + [Fact] + public void AddsWhere_GivenMultipleWhere() + { + var spec1 = new Specification(); + spec1.Query + .Where(x => x.Id > 1) + .Where(x => x.Id > 2); + + var spec2 = new Specification(); + spec2.Query + .Where(x => x.Id > 1) + .Where(x => x.Id > 2); + + spec1.WhereExpressions.Should().HaveCount(2); + spec2.WhereExpressions.Should().HaveCount(2); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Evaluators/OrderEvaluatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Evaluators/OrderEvaluatorTests.cs new file mode 100644 index 00000000..84a1d649 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Evaluators/OrderEvaluatorTests.cs @@ -0,0 +1,111 @@ +namespace Tests.Evaluators; + +public class OrderEvaluatorTests +{ + private static readonly OrderEvaluator _evaluator = OrderEvaluator.Instance; + + public record Customer(int Id, string? Name = null); + + [Fact] + public void OrdersItemsAscending_GivenOrderBy() + { + List input = [new(3), new(1), new(2), new(5), new(4)]; + List expected = [new(1), new(2), new(3), new(4), new(5)]; + + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id); + + Assert(spec, input, expected); + } + + [Fact] + public void OrdersItemsDescending_GivenOrderByDescending() + { + List input = [new(3), new(1), new(2), new(5), new(4)]; + List expected = [new(5), new(4), new(3), new(2), new(1)]; + + var spec = new Specification(); + spec.Query + .OrderByDescending(x => x.Id); + + Assert(spec, input, expected); + } + + [Fact] + public void OrdersItems_GivenOrderByThenBy() + { + List input = [new(3, "c"), new(1, "b"), new(1, "a")]; + List expected = [new(1, "a"), new(1, "b"), new(3, "c")]; + + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id) + .ThenBy(x => x.Name); + + Assert(spec, input, expected); + } + + [Fact] + public void OrdersItems_GivenOrderByThenByDescending() + { + List input = [new(3, "c"), new(1, "a"), new(1, "b")]; + List expected = [new(1, "b"), new(1, "a"), new(3, "c")]; + + var spec = new Specification(); + spec.Query + .OrderBy(x => x.Id) + .ThenByDescending(x => x.Name); + + Assert(spec, input, expected); + } + + [Fact] + public void OrdersItems_GivenOrderByDescendingThenBy() + { + List input = [new(1, "b"), new(1, "a"), new(3, "c")]; + List expected = [new(3, "c"), new(1, "a"), new(1, "b")]; + + var spec = new Specification(); + spec.Query + .OrderByDescending(x => x.Id) + .ThenBy(x => x.Name); + + Assert(spec, input, expected); + } + + [Fact] + public void OrdersItems_GivenOrderByDescendingThenByDescending() + { + List input = [new(1, "a"), new(1, "b"), new(3, "c")]; + List expected = [new(3, "c"), new(1, "b"), new(1, "a")]; + + var spec = new Specification(); + spec.Query + .OrderByDescending(x => x.Id) + .ThenByDescending(x => x.Name); + + Assert(spec, input, expected); + } + + [Fact] + public void DoesNotOrder_GivenNoOrder() + { + List input = [new(3), new(1), new(2), new(5), new(4)]; + List expected = [new(3), new(1), new(2), new(5), new(4)]; + var spec = new Specification(); + + Assert(spec, input, expected); + } + + private static void Assert(Specification spec, List input, List expected) where T : class + { + var actualForIEnumerable = _evaluator.Evaluate(input, spec); + actualForIEnumerable.Should().NotBeNull(); + actualForIEnumerable.Should().Equal(expected); + + var actualForIQueryable = _evaluator.Evaluate(input.AsQueryable(), spec); + actualForIQueryable.Should().NotBeNull(); + actualForIQueryable.Should().Equal(expected); + } +} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchExtension_Like.cs b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchExtensionTests.cs similarity index 88% rename from Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchExtension_Like.cs rename to Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchExtensionTests.cs index b03d5091..ca024fe0 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchExtension_Like.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchExtensionTests.cs @@ -1,8 +1,6 @@ -using System; +namespace Tests.Evaluators; -namespace Ardalis.Specification.UnitTests.EvaluatorTests; - -public class SearchExtension_Like +public class SearchExtensionTests { [Theory] [InlineData(true, "%", "")] @@ -78,7 +76,7 @@ public class SearchExtension_Like [InlineData(true, "%ab%", "aaaab")] [InlineData(true, "%ab%", "aaaaab")] [InlineData(true, "%ab%", "aab")] - public void ReturnsExpectedResult_GivenPatternAndInput(bool expectedResult, string pattern, string input) + public void ReturnsExpected_GivenPatternAndInput(bool expectedResult, string pattern, string input) { var result = input.Like(pattern); @@ -88,10 +86,10 @@ public void ReturnsExpectedResult_GivenPatternAndInput(bool expectedResult, stri [Theory] [InlineData("[", "asd")] [InlineData("[]", "asd")] - public void ShouldThrowInvalidSearchPattern_GivenInvalidPattern(string pattern, string input) + public void ThrowsInvalidSearchPattern_GivenInvalidPattern(string pattern, string input) { - Action action = () => input.Like(pattern); + var sut = () => input.Like(pattern); - action.Should().Throw().WithMessage($"Invalid search pattern: {pattern}"); + sut.Should().Throw().WithMessage($"Invalid search pattern: {pattern}"); } } diff --git a/Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchMemoryEvaluatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchMemoryEvaluatorTests.cs new file mode 100644 index 00000000..9bec8f4d --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SearchMemoryEvaluatorTests.cs @@ -0,0 +1,143 @@ +namespace Tests.Evaluators; + +public class SearchMemoryEvaluatorTests +{ + private static readonly SearchEvaluator _evaluator = SearchEvaluator.Instance; + + public record Customer(int Id, string FirstName, string? LastName); + + [Fact] + public void Filters_GivenSearchInSameGroup() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya"), + //new(4, "aaaa", null) // TODO: Fix null cases. [fatii, 11/02/2025] + ]; + + List expected = + [ + new(1, "axxa", "axya"), + new(3, "aaaa", "axya") + ]; + + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, "%xx%") + .Search(x => x.LastName, "%xy%"); + + // Not materializing with ToList() intentionally to test cloning in the iterator + var actual = _evaluator.Evaluate(input, spec); + + // Multiple iterations will force cloning + actual.Should().HaveSameCount(expected); + actual.Should().Equal(expected); + } + + [Fact] + public void Filters_GivenSearchInDifferentGroup() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya"), + //new(4, "aaaa", null) + ]; + + List expected = + [ + new(1, "axxa", "axya") + ]; + + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, "%xx%", 1) + .Search(x => x.LastName, "%xy%", 2); + + var actual = _evaluator.Evaluate(input, spec).ToList(); + + actual.Should().Equal(expected); + } + + [Fact] + public void Filters_GivenSearchComplexGrouping() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "axxa", "axza"), + //new(4, "aaaa", null), + //new(5, "axxa", null) + ]; + + List expected = + [ + new(1, "axxa", "axya"), + new(3, "axxa", "axza"), + ]; + + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, "%xx%", 1) + .Search(x => x.LastName, "%xy%", 2) + .Search(x => x.LastName, "%xz%", 2); + + var actual = _evaluator.Evaluate(input, spec).ToList(); + + actual.Should().Equal(expected); + } + + [Fact] + public void DoesNotFilter_GivenNoSearch() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya") + ]; + + List expected = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya") + ]; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 0); + + var actual = _evaluator.Evaluate(input, spec); + + actual.Should().Equal(expected); + } + + [Fact] + public void DoesNotFilter_GivenEmptySpec() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya") + ]; + + List expected = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "aaaa"), + new(3, "aaaa", "axya") + ]; + + var spec = new Specification(); + + var actual = _evaluator.Evaluate(input, spec); + + actual.Should().Equal(expected); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Evaluators/SpecificationInMemoryEvaluatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SpecificationInMemoryEvaluatorTests.cs new file mode 100644 index 00000000..ea5988cc --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Evaluators/SpecificationInMemoryEvaluatorTests.cs @@ -0,0 +1,107 @@ +namespace Tests.Evaluators; + +public class SpecificationInMemoryEvaluatorTests +{ + private static readonly InMemorySpecificationEvaluator _evaluator = InMemorySpecificationEvaluator.Default; + + public record Customer(int Id, string FirstName, string LastName); + public record CustomerWithMails(int Id, string FirstName, string LastName, List Emails); + + [Fact] + public void Evaluate_ThrowsSelectorNotFoundException_GivenNoSelector() + { + var spec = new Specification(); + + var sut = () => _evaluator.Evaluate([], spec); + + sut.Should().Throw(); + } + + [Fact] + public void Evaluate_Filters_GivenSpec() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "axya"), + new(3, "aaaa", "axya"), + new(4, "aaaa", "axya") + ]; + + List expected = + [ + new(3, "aaaa", "axya") + ]; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 1) + .Search(x => x.LastName, "%xy%") + .OrderBy(x => x.Id) + .Skip(1) + .Take(1); + + var actual = _evaluator.Evaluate(input, spec).ToList(); + var actualFromSpec = spec.Evaluate(input).ToList(); + + actual.Should().Equal(actualFromSpec); + actual.Should().Equal(expected); + } + + [Fact] + public void Evaluate_Filters_GivenSpecWithSelect() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "axya"), + new(3, "vvvv", "axya"), + new(4, "aaaa", "axya") + ]; + + List expected = ["vvvv"]; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 1) + .Search(x => x.LastName, "%xy%") + .OrderBy(x => x.Id) + .Skip(1) + .Take(1); + spec.Query.Select(x => x.FirstName); + + var actual = _evaluator.Evaluate(input, spec).ToList(); + var actualFromSpec = spec.Evaluate(input).ToList(); + + actual.Should().Equal(actualFromSpec); + actual.Should().Equal(expected); + } + + [Fact] + public void Evaluate_DoesNotFilter_GivenEmptySpec() + { + List input = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "axya"), + new(3, "aaaa", "axya"), + new(4, "aaaa", "axya") + ]; + + List expected = + [ + new(1, "axxa", "axya"), + new(2, "aaaa", "axya"), + new(3, "aaaa", "axya"), + new(4, "aaaa", "axya") + ]; + + var spec = new Specification(); + + var actual = _evaluator.Evaluate(input, spec).ToList(); + var actualFromSpec = spec.Evaluate(input).ToList(); + + actual.Should().Equal(actualFromSpec); + actual.Should().Equal(expected); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Evaluators/WhereEvaluatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Evaluators/WhereEvaluatorTests.cs new file mode 100644 index 00000000..4184246a --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Evaluators/WhereEvaluatorTests.cs @@ -0,0 +1,43 @@ +namespace Tests.Evaluators; + +public class WhereEvaluatorTests +{ + private static readonly WhereEvaluator _evaluator = WhereEvaluator.Instance; + + public record Customer(int Id); + + [Fact] + public void Filters_GivenWhereExpression() + { + List input = [new(1), new(2), new(3), new(4), new(5)]; + List expected = [new(4), new(5)]; + + var spec = new Specification(); + spec.Query + .Where(x => x.Id > 3); + + Assert(spec, input, expected); + } + + [Fact] + public void DoesNotFilter_GivenNoWhereExpression() + { + List input = [new(1), new(2), new(3), new(4), new(5)]; + List expected = [new(1), new(2), new(3), new(4), new(5)]; + + var spec = new Specification(); + + Assert(spec, input, expected); + } + + private static void Assert(Specification spec, List input, List expected) where T : class + { + var actualForIEnumerable = _evaluator.Evaluate(input, spec); + actualForIEnumerable.Should().NotBeNull(); + actualForIEnumerable.Should().Equal(expected); + + var actualForIQueryable = _evaluator.Evaluate(input.AsQueryable(), spec); + actualForIQueryable.Should().NotBeNull(); + actualForIQueryable.Should().Equal(expected); + } +} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/ConcurrentSelectorsExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/ConcurrentSelectorsExceptionTests.cs similarity index 93% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/ConcurrentSelectorsExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/ConcurrentSelectorsExceptionTests.cs index 9c81ce3c..a6b28be3 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/ConcurrentSelectorsExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/ConcurrentSelectorsExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class ConcurrentSelectorsExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateOrderChainExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateOrderChainExceptionTests.cs similarity index 92% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateOrderChainExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateOrderChainExceptionTests.cs index 7b3555c8..01a17e80 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateOrderChainExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateOrderChainExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class DuplicateOrderChainExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateSkipExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateSkipExceptionTests.cs similarity index 92% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateSkipExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateSkipExceptionTests.cs index e3955abf..fc5c6f15 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateSkipExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateSkipExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class DuplicateSkipExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateTakeExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateTakeExceptionTests.cs similarity index 92% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateTakeExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateTakeExceptionTests.cs index 5dc9c0bc..29c15718 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/DuplicateTakeExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/DuplicateTakeExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class DuplicateTakeExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/InvalidSearchPatternExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/InvalidSearchPatternExceptionTests.cs similarity index 92% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/InvalidSearchPatternExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/InvalidSearchPatternExceptionTests.cs index 4a28fdef..9e7b80fe 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/InvalidSearchPatternExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/InvalidSearchPatternExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class InvalidSearchPatternExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/SelectorNotFoundExceptionTests.cs b/Specification/tests/Ardalis.Specification.Tests/Exceptions/SelectorNotFoundExceptionTests.cs similarity index 92% rename from Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/SelectorNotFoundExceptionTests.cs rename to Specification/tests/Ardalis.Specification.Tests/Exceptions/SelectorNotFoundExceptionTests.cs index 5a4aec05..7dbbd798 100644 --- a/Specification/tests/Ardalis.Specification.UnitTests/ExceptionTests/SelectorNotFoundExceptionTests.cs +++ b/Specification/tests/Ardalis.Specification.Tests/Exceptions/SelectorNotFoundExceptionTests.cs @@ -1,6 +1,4 @@ -using System; - -namespace Ardalis.Specification.UnitTests; +namespace Tests.Exceptions; public class SelectorNotFoundExceptionTests { diff --git a/Specification/tests/Ardalis.Specification.Tests/GlobalUsings.cs b/Specification/tests/Ardalis.Specification.Tests/GlobalUsings.cs new file mode 100644 index 00000000..0e11687c --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/GlobalUsings.cs @@ -0,0 +1,7 @@ +global using Ardalis.Specification; +global using FluentAssertions; +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using System.Linq.Expressions; +global using Xunit; diff --git a/Specification/tests/Ardalis.Specification.Tests/Validators/LikeValidatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Validators/LikeValidatorTests.cs new file mode 100644 index 00000000..10544926 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Validators/LikeValidatorTests.cs @@ -0,0 +1,161 @@ +namespace Tests.Validators; + +public class SearchValidatorTests +{ + private static readonly SearchValidator _validator = SearchValidator.Instance; + + public record Customer(int Id, string FirstName, string? LastName); + + [Fact] + public void ReturnsTrue_GivenEmptySpec() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var spec = new Specification(); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsTrue_GivenNoSearch() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 1); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithSingleSearch_WithValidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "irst"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithSingleSearch_WithInvalidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "irstt"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithMultipleSearchSameGroup_WithValidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "irst"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%") + .Search(x => x.LastName, $"%{term}%"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithMultipleSearchSameGroup_WithInvalidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "irstt"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%") + .Search(x => x.LastName, $"%{term}%"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithMultipleSearchDifferentGroup_WithValidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "Name"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%", 1) + .Search(x => x.LastName, $"%{term}%", 2); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithMultipleSearchDifferentGroup_WithInvalidEntity() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var term = "irst"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%", 1) + .Search(x => x.LastName, $"%{term}%", 2); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithMultipleSearchSameGroup_WithNullProperty() + { + var customer = new Customer(1, "FirstName1", null); + + var term = "irst"; + var spec = new Specification(); + spec.Query + .Search(x => x.FirstName, $"%{term}%", 1) + .Search(x => x.LastName, $"%{term}%", 1); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + // TODO: Fix null support in SearchValidator [fatii, 11/02/2025] + //[Fact] + //public void ReturnsFalse_GivenSpecWithMultipleSearchDifferentGroup_WithNullProperty() + //{ + // var customer = new Customer(1, "FirstName1", null); + + // var term = "irst"; + // var spec = new Specification(); + // spec.Query + // .Search(x => x.FirstName, $"%{term}%", 1) + // .Search(x => x.LastName, $"%{term}%", 2); + + // var result = _validator.IsValid(customer, spec); + + // result.Should().BeFalse(); + //} +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Validators/SpecificationValidatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Validators/SpecificationValidatorTests.cs new file mode 100644 index 00000000..ed28c513 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Validators/SpecificationValidatorTests.cs @@ -0,0 +1,76 @@ +namespace Tests.Validators; + +public class SpecificationValidatorTests +{ + private static readonly SpecificationValidator _validatorDefault = SpecificationValidator.Default; + + public record Customer(int Id, string FirstName, string LastName); + + [Fact] + public void ReturnTrue_GivenAllValidatorsPass() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var searchTerm = "irst"; + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 1) + .Search(x => x.FirstName, $"%{searchTerm}%"); + + var result = _validatorDefault.IsValid(customer, spec); + var resultFromSpec = spec.IsSatisfiedBy(customer); + + result.Should().Be(resultFromSpec); + result.Should().BeTrue(); + } + + [Fact] + public void ReturnTrue_GivenEmptySpec() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var spec = new Specification(); + + var result = _validatorDefault.IsValid(customer, spec); + var resultFromSpec = spec.IsSatisfiedBy(customer); + + result.Should().Be(resultFromSpec); + result.Should().BeTrue(); + } + + [Fact] + public void ReturnFalse_GivenOneValidatorFails() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var searchTerm = "irst"; + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 1) + .Search(x => x.FirstName, $"%{searchTerm}%"); + + var result = _validatorDefault.IsValid(customer, spec); + var resultFromSpec = spec.IsSatisfiedBy(customer); + + result.Should().Be(resultFromSpec); + result.Should().BeTrue(); + } + + [Fact] + public void ReturnFalse_GivenAllValidatorsFail() + { + var customer = new Customer(1, "FirstName1", "LastName1"); + + var searchTerm = "irstt"; + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 2) + .Search(x => x.FirstName, $"%{searchTerm}%"); + + var result = _validatorDefault.IsValid(customer, spec); + var resultFromSpec = spec.IsSatisfiedBy(customer); + + result.Should().Be(resultFromSpec); + result.Should().BeFalse(); + } +} diff --git a/Specification/tests/Ardalis.Specification.Tests/Validators/WhereValidatorTests.cs b/Specification/tests/Ardalis.Specification.Tests/Validators/WhereValidatorTests.cs new file mode 100644 index 00000000..b81a4ac5 --- /dev/null +++ b/Specification/tests/Ardalis.Specification.Tests/Validators/WhereValidatorTests.cs @@ -0,0 +1,93 @@ +namespace Tests.Validators; + +public class WhereValidatorTests +{ + private static readonly WhereValidator _validator = WhereValidator.Instance; + + public record Customer(int Id, string Name); + + [Fact] + public void ReturnsTrue_GivenEmptySpec() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithSingleWhere_WithValidEntity() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 1); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithSingleWhere_WithInvalidEntity() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 2); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } + + [Fact] + public void ReturnsTrue_GivenSpecWithMultipleWhere_WithValidEntity() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 1) + .Where(x => x.Name == "Customer1"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeTrue(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithMultipleWhere_WithSingleInvalidValue() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 2) + .Where(x => x.Name == "Customer1"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } + + [Fact] + public void ReturnsFalse_GivenSpecWithMultipleWhere_WithAllInvalidValues() + { + var customer = new Customer(1, "Customer1"); + + var spec = new Specification(); + spec.Query + .Where(x => x.Id == 2) + .Where(x => x.Name == "Customer2"); + + var result = _validator.IsValid(customer, spec); + + result.Should().BeFalse(); + } +} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/IncludableBuilderExtensions_ThenInclude.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/IncludableBuilderExtensions_ThenInclude.cs deleted file mode 100644 index a48ef27f..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/IncludableBuilderExtensions_ThenInclude.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests; - -public class IncludableBuilderExtensions_ThenInclude -{ - [Fact] - public void AppendIncludeExpressionInfoToListWithTypeThenInclude_GivenThenIncludeExpression() - { - var spec = new StoreIncludeCompanyThenCountrySpec(); - - var includeExpressions = spec.IncludeExpressions.ToList(); - - // The list must have two items, since ThenInclude can be applied once the first level is applied. - includeExpressions.Should().HaveCount(2); - - includeExpressions[1].Type.Should().Be(IncludeTypeEnum.ThenInclude); - } - - [Fact] - public void AddsNothingToList_GivenDiscardedIncludeChain() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.IncludeExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenThenIncludeExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditionsForInnerChains(1); - - spec.IncludeExpressions.Should().HaveCount(1); - spec.IncludeExpressions.First().Type.Should().Be(IncludeTypeEnum.Include); - spec.IncludeExpressions.Where(x => x.Type == IncludeTypeEnum.ThenInclude).Should().BeEmpty(); - } - - [Fact] - public void ThenInclude_Append_IncludeExpressionInfo_With_EnumerablePreviousPropertyType() - { - var spec = new StoreIncludeCompanyThenStoresSpec(); - - var includeExpressions = spec.IncludeExpressions.ToList(); - - includeExpressions.Should().HaveCount(3); - - includeExpressions[2].PreviousPropertyType.Should().Be(typeof(IEnumerable)); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenBy.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenBy.cs deleted file mode 100644 index 7a759f89..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenBy.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class OrderedBuilderExtensions_ThenBy -{ - [Fact] - public void AppendOrderExpressionToListWithThenByType_GivenThenByExpression() - { - var spec = new StoresByCompanyOrderedDescByNameThenByIdSpec(1); - - var orderExpressions = spec.OrderExpressions.ToList(); - - // The list must have two items, since Then can be applied once the first level is applied. - orderExpressions.Should().HaveCount(2); - - orderExpressions[1].OrderType.Should().Be(OrderTypeEnum.ThenBy); - } - - [Fact] - public void AddsNothingToList_GivenDiscardedOrderChain() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenThenByExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditionsForInnerChains(1); - - spec.OrderExpressions.Should().HaveCount(2); - spec.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); - spec.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.OrderByDescending); - spec.OrderExpressions.Where(x => x.OrderType == OrderTypeEnum.ThenBy).Should().BeEmpty(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenByDescending.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenByDescending.cs deleted file mode 100644 index fe67a494..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/OrderedBuilderExtensions_ThenByDescending.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class OrderedBuilderExtensions_ThenByDescending -{ - [Fact] - public void AppendsOrderExpressionToListWithThenByDescendingType_GivenThenByDescendingExpression() - { - var spec = new StoresByCompanyOrderedDescByNameThenByDescIdSpec(1); - - var orderExpressions = spec.OrderExpressions.ToList(); - - // The list must have two items, since Then can be applied once the first level is applied. - orderExpressions.Should().HaveCount(2); - - orderExpressions[1].OrderType.Should().Be(OrderTypeEnum.ThenByDescending); - } - - [Fact] - public void AddsNothingToList_GivenDiscardedOrderChain() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenThenByDescendingExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditionsForInnerChains(1); - - spec.OrderExpressions.Should().HaveCount(2); - spec.OrderExpressions.First().OrderType.Should().Be(OrderTypeEnum.OrderBy); - spec.OrderExpressions.Skip(1).First().OrderType.Should().Be(OrderTypeEnum.OrderByDescending); - spec.OrderExpressions.Where(x => x.OrderType == OrderTypeEnum.ThenByDescending).Should().BeEmpty(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTracking.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTracking.cs deleted file mode 100644 index 3caf3983..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTracking.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests.BuilderTests; - -public class SpecificationBuilderExtensions_AsNoTracking -{ - [Fact] - public void DoesNothing_GivenSpecWithoutAsNoTracking() - { - var spec = new StoreEmptySpec(); - - spec.AsNoTracking.Should().Be(false); - } - - [Fact] - public void DoesNothing_GivenAsNoTrackingWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.AsNoTracking.Should().Be(false); - } - - [Fact] - public void FlagsAsNoTracking_GivenSpecWithAsNoTracking() - { - var spec = new CompanyByIdAsUntrackedSpec(1); - - spec.AsNoTracking.Should().Be(true); - } - - [Fact] - public void FlagsAsNoTracking_GivenSpecWithAsTrackingAndEndWithAsNoTracking() - { - var spec = new CompanyByIdWithAsTrackingAsUntrackedSpec(1); - - spec.AsNoTracking.Should().Be(true); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTrackingWithIdentityResolution.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTrackingWithIdentityResolution.cs deleted file mode 100644 index d6a20829..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsNoTrackingWithIdentityResolution.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests.BuilderTests; - -public class SpecificationBuilderExtensions_AsNoTrackingWithIdentityResolution -{ - [Fact] - public void DoesNothing_GivenSpecWithoutAsNoTrackingWithIdentityResolution() - { - var spec = new StoreEmptySpec(); - - spec.AsNoTrackingWithIdentityResolution.Should().Be(false); - } - - [Fact] - public void DoesNothing_GivenAsNoTrackingWithIdentityResolutionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.AsNoTrackingWithIdentityResolution.Should().Be(false); - } - - [Fact] - public void FlagsAsNoTracking_GivenSpecWithAsNoTrackingWithIdentityResolution() - { - var spec = new CompanyByIdAsUntrackedWithIdentityResolutionSpec(1); - - spec.AsNoTrackingWithIdentityResolution.Should().Be(true); - } - - [Fact] - public void FlagsAsNoTracking_GivenSpecWithAsTrackingAndEndWithAsNoTrackingWithIdentityResolution() - { - var spec = new CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec(1); - - spec.AsNoTrackingWithIdentityResolution.Should().Be(true); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsSplitQuery.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsSplitQuery.cs deleted file mode 100644 index 58260597..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsSplitQuery.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Ardalis.Specification.UnitTests.BuilderTests; - -public class SpecificationBuilderExtensions_AsSplitQuery -{ - [Fact] - public void DoesNothing_GivenSpecWithoutAsSplitQuery() - { - var spec = new StoreEmptySpec(); - - spec.AsSplitQuery.Should().Be(false); - } - - [Fact] - public void DoesNothing_GivenAsSplitQueryWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.AsSplitQuery.Should().Be(false); - } - - [Fact] - public void FlagsAsNoTracking_GivenSpecWithAsSplitQuery() - { - var spec = new CompanyByIdAsSplitQuery(1); - - spec.AsSplitQuery.Should().Be(true); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsTracking.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsTracking.cs deleted file mode 100644 index a8b2c75b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_AsTracking.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests.BuilderTests; - -public class SpecificationBuilderExtensions_AsTracking -{ - [Fact] - public void DoesNothing_GivenSpecWithoutAsTracking() - { - var spec = new StoreEmptySpec(); - - spec.AsTracking.Should().Be(false); - } - - [Fact] - public void DoesNothing_GivenAsTrackingWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.AsTracking.Should().Be(false); - } - - [Fact] - public void FlagsAsTracking_GivenSpecWithAsTracking() - { - var spec = new CompanyByIdAsTrackedSpec(1); - - spec.AsTracking.Should().Be(true); - } - - [Fact] - public void FlagsAsTracking_GivenSpecWithAsNoTrackingAndEndWithAsTracking() - { - var spec = new CompanyByIdWithAsNoTrackingAsTrackedSpec(1); - - spec.AsTracking.Should().Be(true); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IgnoreQueryFilters.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IgnoreQueryFilters.cs deleted file mode 100644 index 74e79f25..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IgnoreQueryFilters.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Ardalis.Specification.UnitTests.BuilderTests; - -public class SpecificationBuilderExtensions_IgnoreQueryFilters -{ - [Fact] - public void DoesNothing_GivenSpecWithoutIgnoreQueryFilters() - { - var spec = new StoreEmptySpec(); - - spec.IgnoreQueryFilters.Should().Be(false); - } - - [Fact] - public void DoesNothing_GivenIgnoreQueryFiltersWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.IgnoreQueryFilters.Should().Be(false); - } - - [Fact] - public void FlagsIgnoreQueryFilters_GivenSpecWithIgnoreQueryFilters() - { - var spec = new CompanyByIdIgnoreQueryFilters(1); - - spec.IgnoreQueryFilters.Should().Be(true); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Include.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Include.cs deleted file mode 100644 index a1e12aeb..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Include.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Include -{ - [Fact] - public void AddsNothingToList_GivenNoIncludeExpression() - { - var spec = new StoreEmptySpec(); - - spec.IncludeExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenIncludeExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.IncludeExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsIncludeExpressionInfoToListWithTypeInclude_GivenIncludeExpression() - { - var spec = new StoreIncludeAddressSpec(); - - spec.IncludeExpressions.Should().ContainSingle(); - spec.IncludeExpressions.Single().Type.Should().Be(IncludeTypeEnum.Include); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IncludeString.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IncludeString.cs deleted file mode 100644 index eaf1c44f..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_IncludeString.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_IncludeString -{ - [Fact] - public void AddsNothingToList_GivenNoIncludeStringExpression() - { - var spec = new StoreEmptySpec(); - - spec.WhereExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenIncludeStringWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.IncludeStrings.Should().BeEmpty(); - } - - [Fact] - public void AddsIncludeStringToList_GivenString() - { - var spec = new StoreIncludeCompanyThenCountryAsStringSpec(); - - var expected = $"{nameof(Company)}.{nameof(Company.Country)}"; - - spec.IncludeStrings.Should().ContainSingle(); - spec.IncludeStrings.Single().Should().Be(expected); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderBy.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderBy.cs deleted file mode 100644 index e5b96c70..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderBy.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_OrderBy -{ - [Fact] - public void AddsNothingToList_GivenNoOrderExpression() - { - var spec = new StoreEmptySpec(); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenOrderExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsOrderExpressionToListWithOrderByType_GivenOrderByExpression() - { - var spec = new StoresOrderedSpecByName(); - - spec.OrderExpressions.Should().ContainSingle(); - spec.OrderExpressions.Single().OrderType.Should().Be(OrderTypeEnum.OrderBy); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderByDescending.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderByDescending.cs deleted file mode 100644 index 42f586e8..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_OrderByDescending.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_OrderByDescending -{ - [Fact] - public void AddsNothingToList_GivenNoOrderExpression() - { - var spec = new StoreEmptySpec(); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenOrderExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.OrderExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsOrderExpressionToListWithOrderByDescendingType_GivenOrderByDescendingExpression() - { - var spec = new StoresOrderedDescendingByNameSpec(); - - spec.OrderExpressions.Should().ContainSingle(); - spec.OrderExpressions.Single().OrderType.Should().Be(OrderTypeEnum.OrderByDescending); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_PostProcessingAction.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_PostProcessingAction.cs deleted file mode 100644 index cd6bfb68..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_PostProcessingAction.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_PostProcessingAction -{ - [Fact] - public void SetsNothing_GivenNoPostProcessingAction() - { - var spec = new StoreEmptySpec(); - - spec.PostProcessingAction.Should().BeNull(); - } - - [Fact] - public void SetsNothing_GivenSelectorSpecWithNoPostProcessingAction() - { - var spec = new StoreNamesEmptySpec(); - - spec.PostProcessingAction.Should().BeNull(); - } - - [Fact] - public void SetsPostProcessingPredicate_GivenPostProcessingAction() - { - var spec = new StoreWithPostProcessingActionSpec(); - - spec.PostProcessingAction.Should().NotBeNull(); - } - - [Fact] - public void SetsPostProcessingPredicate_GivenSelectorSpecWithPostProcessingAction() - { - var spec = new StoreNamesWithPostProcessingActionSpec(); - - spec.PostProcessingAction.Should().NotBeNull(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Search.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Search.cs deleted file mode 100644 index cb32a075..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Search.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Search -{ - [Fact] - public void AddsNothingToList_GivenNoWhereExpression() - { - var spec = new StoreEmptySpec(); - - spec.SearchCriterias.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenSearchExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.SearchCriterias.Should().BeEmpty(); - } - - [Fact] - public void AddsOneCriteriaWithDefaultGroupToList_GivenOneSearchExpressionWithNoGroup() - { - var spec = new StoreSearchByNameSpec("test"); - - spec.SearchCriterias.Should().ContainSingle(); - spec.SearchCriterias.Single().SearchTerm.Should().Be("%test%"); - spec.SearchCriterias.Single().SearchGroup.Should().Be(1); - } - - [Fact] - public void AddsTwoCriteriaWithSameGroupToList_GivenTwoSearchExpressionWithNoGroup() - { - var spec = new StoreSearchByNameOrCitySpec("test"); - - var criterias = spec.SearchCriterias.ToList(); - - criterias.Should().HaveCount(2); - criterias.ForEach(x => x.SearchTerm.Should().Be("%test%")); - criterias.ForEach(x => x.SearchGroup.Should().Be(1)); - } - - [Fact] - public void AddsTwoCriteriaWithDifferentGroupToList_GivenTwoSearchExpressionWithDistinctGroup() - { - var spec = new StoreSearchByNameAndCitySpec("test"); - - var criterias = spec.SearchCriterias.ToList(); - - criterias.Should().HaveCount(2); - criterias.ForEach(x => x.SearchTerm.Should().Be("%test%")); - criterias[0].SearchGroup.Should().Be(1); - criterias[1].SearchGroup.Should().Be(2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Select.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Select.cs deleted file mode 100644 index d979a9a8..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Select.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Select -{ - [Fact] - public void SetsNothing_GivenNoSelectExpression() - { - var spec = new StoreNamesEmptySpec(); - - spec.Selector.Should().BeNull(); - } - - [Fact] - public void SetsSelector_GivenSelectExpression() - { - var spec = new StoreNamesSpec(); - - spec.Selector.Should().NotBeNull(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_SelectMany.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_SelectMany.cs deleted file mode 100644 index 18ffd968..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_SelectMany.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_SelectMany -{ - [Fact] - public void SetsNothing_GivenNoSelectManyExpression() - { - var spec = new StoreProductNamesEmptySpec(); - - spec.SelectorMany.Should().BeNull(); - } - - [Fact] - public void SetsSelectorMany_GivenSelectManyExpression() - { - var spec = new StoreProductNamesSpec(); - - spec.SelectorMany.Should().NotBeNull(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Skip.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Skip.cs deleted file mode 100644 index afffca84..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Skip.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Skip -{ - [Fact] - public void SetsSkipProperty_GivenValue() - { - var skip = 1; - - var spec = new StoreNamesPaginatedSpec(skip, 10); - - spec.Skip.Should() - .Be(skip); - } - - [Fact] - public void DoesNothing_GivenSkipWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.Skip.Should().BeNull(); - } - - [Fact] - public void ThrowsDuplicateSkipException_GivenSkipUsedMoreThanOnce() - { - Action sutAction = () => new StoreDuplicateSkipSpec(); - - sutAction.Should() - .Throw() - .WithMessage("Duplicate use of Skip(). Ensure you don't use Skip() more than once in the same specification!"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Take.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Take.cs deleted file mode 100644 index 4c976e4b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Take.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Take -{ - [Fact] - public void SetsTakeProperty_GivenValue() - { - var take = 10; - var spec = new StoreNamesPaginatedSpec(0, take); - - spec.Take.Should().Be(take); - } - - [Fact] - public void DoesNothing_GivenTakeWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.Take.Should().BeNull(); - } - - [Fact] - public void ThrowsDuplicateTakeException_GivenTakeUsedMoreThanOnce() - { - Action sutAction = () => new StoreDuplicateTakeSpec(); - - sutAction.Should() - .Throw() - .WithMessage("Duplicate use of Take(). Ensure you don't use Take() more than once in the same specification!"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Where.cs b/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Where.cs deleted file mode 100644 index 7a14457d..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/BuilderTests/SpecificationBuilderExtensions_Where.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ardalis.Specification.UnitTests; - -public class SpecificationBuilderExtensions_Where -{ - [Fact] - public void AddsNothingToList_GivenNoWhereExpression() - { - var spec = new StoreEmptySpec(); - - spec.WhereExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsNothingToList_GivenWhereExpressionWithFalseCondition() - { - var spec = new CompanyByIdWithFalseConditions(1); - - spec.WhereExpressions.Should().BeEmpty(); - } - - [Fact] - public void AddsOneExpressionToList_GivenOneWhereExpression() - { - var spec = new StoreByIdSpec(1); - - spec.WhereExpressions.Should().ContainSingle(); - } - - [Fact] - public void AddsTwoExpressionsToList_GivenTwoWhereExpressions() - { - var spec = new StoreByIdAndNameSpec(1, "name"); - - spec.WhereExpressions.Should().HaveCount(2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/InMemorySpecificationEvaluatorTests.cs b/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/InMemorySpecificationEvaluatorTests.cs deleted file mode 100644 index d856c4d5..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/InMemorySpecificationEvaluatorTests.cs +++ /dev/null @@ -1,146 +0,0 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; -using System; - -namespace Ardalis.Specification.UnitTests; - -public class InMemorySpecificationEvaluatorTests -{ - [Fact] - public void ReturnsStoreWithId10_GivenStoreByIdSpec() - { - var spec = new StoreByIdSpec(10); - - var store = spec.Evaluate(StoreSeed.Get()).FirstOrDefault(); - - store?.Id.Should().Be(10); - } - - [Fact] - public void ReturnsStoreWithIdFrom15To30_GivenStoresByIdListSpec() - { - var ids = Enumerable.Range(15, 16); - var spec = new StoresByIdListSpec(ids); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.Count().Should().Be(16); - stores.OrderBy(x => x.Id).First().Id.Should().Be(15); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(30); - } - - [Fact] - public void ReturnsSecondPageOfStoreNames_GivenStoreNamesPaginatedSpec() - { - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoreNamesPaginatedSpec(skip, take); - - var storeNames = spec.Evaluate(StoreSeed.Get()); - - storeNames.Count().Should().Be(take); - storeNames.First().Should().Be("Store 11"); - storeNames.Last().Should().Be("Store 20"); - } - - [Fact] - public void ReturnsSecondPageOfStores_GivenStoresPaginatedSpec() - { - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresPaginatedSpec(skip, take); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.Count().Should().Be(take); - stores.OrderBy(x => x.Id).First().Id.Should().Be(11); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(20); - } - - [Fact] - public void ReturnsOrderStoresByNameDescForCompanyWithId2_GivenStoresByCompanyOrderedDescByNameSpec() - { - var spec = new StoresByCompanyOrderedDescByNameSpec(2); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_LAST_ID); - } - - [Fact] - public void ReturnsOrderStoresByNameDescThenByIdForCompanyWithId2_GivenStoresByCompanyOrderedDescByNameThenByIdSpec() - { - var spec = new StoresByCompanyOrderedDescByNameThenByIdSpec(2); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.First().Id.Should().Be(99); - stores.Last().Id.Should().Be(98); - } - - [Fact] - public void ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompanyPaginatedOrderedDescByNameSpec() - { - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresByCompanyPaginatedOrderedDescByNameSpec(2, skip, take); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.Count().Should().Be(take); - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_PAGE2_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FOR_COMPANY2_PAGE2_LAST_ID); - } - - [Fact] - public void ReturnsSecondPageOfStoresForCompanyWithId2_GivenStoresByCompanyPaginatedSpec() - { - var take = 10; // pagesize 10 - var skip = (2 - 1) * 10; // page 2 - - var spec = new StoresByCompanyPaginatedSpec(2, skip, take); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.Count().Should().Be(take); - stores.OrderBy(x => x.Id).First().Id.Should().Be(61); - stores.OrderBy(x => x.Id).Last().Id.Should().Be(70); - } - - [Fact] - public void ReturnsOrderedStores_GivenStoresOrderedSpecByName() - { - var spec = new StoresOrderedSpecByName(); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_LAST_ID); - } - - [Fact] - public void ReturnsOrderedStores_GivenStoresOrderedDescendingByNameSpec() - { - var spec = new StoresOrderedDescendingByNameSpec(); - - var stores = spec.Evaluate(StoreSeed.Get()); - - stores.First().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_FIRST_ID); - stores.Last().Id.Should().Be(StoreSeed.ORDERED_BY_NAME_DESC_LAST_ID); - } - - [Fact] - public void ThrowsDuplicateOrderChainException_GivenSpecWithMultipleOrderChains() - { - var spec = new StoresOrderedTwoChainsSpec(); - - Action sutAction = () => spec.Evaluate(StoreSeed.Get()); - - sutAction.Should() - .Throw() - .WithMessage("The specification contains more than one Order chain!"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchEvaluator_Evaluate.cs b/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchEvaluator_Evaluate.cs deleted file mode 100644 index 9d9da4d3..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchEvaluator_Evaluate.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests; - -public class SearchEvaluator_Evaluate -{ - private static readonly List _people = new() - { - new Person("James"), - new Person("Robert"), - new Person("Mary"), - new Person("Linda"), - new Person("Michael"), - new Person("David"), - }; - - [Theory] - [InlineData("%mes", 1)] - [InlineData("%r%", 2)] - [InlineData("_inda", 1)] - [InlineData("M%", 2)] - [InlineData("[RM]%", 3)] - [InlineData("_[IA]%", 5)] - public void ReturnsFilteredList_GivenSearchExpression(string searchTerm, int expectedCount) - { - var result = SearchEvaluator.Instance.Evaluate(_people, new PersonSpecification(searchTerm)); - - result.Should().HaveCount(expectedCount); - } -} - -public class PersonSpecification : Specification -{ - public PersonSpecification(string searchTerm) - { - Query.Search(x => x.Name, searchTerm); - } -} - -public class Person -{ - public string Name { get; } - - public Person(string name) - { - Name = name; - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsSplitQuery.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsSplitQuery.cs deleted file mode 100644 index 7bf8fa03..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsSplitQuery.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdAsSplitQuery : Specification, ISingleResultSpecification -{ - public CompanyByIdAsSplitQuery(int id) - { - Query.Where(company => company.Id == id) - .Include(x => x.Stores) - .ThenInclude(x => x.Products) - .AsSplitQuery(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsTrackedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsTrackedSpec.cs deleted file mode 100644 index 9775a9bd..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsTrackedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdAsTrackedSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdAsTrackedSpec(int id) - { - Query.Where(company => company.Id == id).AsTracking(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedSpec.cs deleted file mode 100644 index 362a76ae..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdAsUntrackedSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdAsUntrackedSpec(int id) - { - Query.Where(company => company.Id == id).AsNoTracking(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedWithIdentityResolutionSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedWithIdentityResolutionSpec.cs deleted file mode 100644 index 26e73bdd..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdAsUntrackedWithIdentityResolutionSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdAsUntrackedWithIdentityResolutionSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdAsUntrackedWithIdentityResolutionSpec(int id) - { - Query.Where(company => company.Id == id).AsNoTrackingWithIdentityResolution(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIgnoreQueryFilters.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIgnoreQueryFilters.cs deleted file mode 100644 index 84107c8b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIgnoreQueryFilters.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdIgnoreQueryFilters : Specification, ISingleResultSpecification -{ - public CompanyByIdIgnoreQueryFilters(int id) - { - Query.Where(company => company.Id == id).IgnoreQueryFilters(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresSpec.cs deleted file mode 100644 index 4eea283f..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdIncludeStoresSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdIncludeStoresSpec(int companyId) - { - Query.Where(x => x.Id == companyId).Include(x => x.Stores); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeAddressSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeAddressSpec.cs deleted file mode 100644 index 00136d09..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeAddressSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdIncludeStoresThenIncludeAddressSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdIncludeStoresThenIncludeAddressSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(x => x.Stores) - .ThenInclude(x => x.Address); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeProductsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeProductsSpec.cs deleted file mode 100644 index 5e492a84..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdIncludeStoresThenIncludeProductsSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdIncludeStoresThenIncludeProductsSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdIncludeStoresThenIncludeProductsSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(x => x.Stores) - .ThenInclude(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdSpec.cs deleted file mode 100644 index 4e3b3123..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdSpec(int id) - { - Query.Where(company => company.Id == id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsNoTrackingAsTrackedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsNoTrackingAsTrackedSpec.cs deleted file mode 100644 index 5b08268e..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsNoTrackingAsTrackedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdWithAsNoTrackingAsTrackedSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdWithAsNoTrackingAsTrackedSpec(int id) - { - Query.Where(company => company.Id == id).AsNoTracking().AsNoTrackingWithIdentityResolution().AsTracking(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedSpec.cs deleted file mode 100644 index a7db5988..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdWithAsTrackingAsUntrackedSpec : Specification, ISingleResultSpecification -{ - public CompanyByIdWithAsTrackingAsUntrackedSpec(int id) - { - Query.Where(company => company.Id == id).AsTracking().AsNoTracking(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec.cs deleted file mode 100644 index 1427bf25..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec : Specification, - ISingleResultSpecification -{ - public CompanyByIdWithAsTrackingAsUntrackedWithIdentityResolutionSpec(int id) - { - Query.Where(company => company.Id == id).AsTracking().AsNoTrackingWithIdentityResolution(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditions.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditions.cs deleted file mode 100644 index 6b6af030..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditions.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdWithFalseConditions : Specification, ISingleResultSpecification -{ - public CompanyByIdWithFalseConditions(int id) - { - Query.Where(x => x.Id == id, false) - .OrderBy(x => x.Id, false) - .ThenBy(x => x.Name) - .ThenByDescending(x => x.Name) - .OrderByDescending(x => x.Id, false) - .ThenBy(x => x.Name) - .ThenByDescending(x => x.Name) - .Include(x => x.Stores, false) - .ThenInclude(x => x.Products) - .Include(nameof(Store), false) - .Take(10, false) - .Skip(10, false) - .AsNoTracking(false) - .AsNoTrackingWithIdentityResolution(false) - .AsSplitQuery(false) - .IgnoreQueryFilters(false) - .Search(x => x.Name!, "asd", false) - .EnableCache(nameof(CompanyByIdWithFalseConditions), false, id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditionsForInnerChains.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditionsForInnerChains.cs deleted file mode 100644 index 196a8c96..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/CompanyByIdWithFalseConditionsForInnerChains.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyByIdWithFalseConditionsForInnerChains : Specification, ISingleResultSpecification -{ - public CompanyByIdWithFalseConditionsForInnerChains(int id) - { - Query.Where(x => x.Id == id, false) - .OrderBy(x => x.Id) - .ThenBy(x => x.Name, false) - .ThenByDescending(x => x.Name) - .OrderByDescending(x => x.Id) - .ThenByDescending(x => x.Name, false) - .ThenBy(x => x.Name) - .Include(x => x.Stores) - .ThenInclude(x => x.Products, false) - .ThenInclude(x => x.Store) - .Include(nameof(Store), false) - .Take(10, false) - .Skip(10, false) - .AsNoTracking(false) - .AsNoTrackingWithIdentityResolution(false) - .AsSplitQuery(false) - .IgnoreQueryFilters(false) - .Search(x => x.Name!, "asd", false) - .EnableCache(nameof(CompanyByIdWithFalseConditions), false, id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsTrackedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsTrackedSpec.cs deleted file mode 100644 index 00991906..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsTrackedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class ProductByIdAsTrackedSpec : Specification, ISingleResultSpecification -{ - public ProductByIdAsTrackedSpec(int id) - { - Query.Where(product => product.Id == id).AsTracking(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsUntrackedWithIdentityResolutionSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsUntrackedWithIdentityResolutionSpec.cs deleted file mode 100644 index 690422ad..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdAsUntrackedWithIdentityResolutionSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class ProductByIdAsUntrackedWithIdentityResolutionSpec : Specification, ISingleResultSpecification -{ - public ProductByIdAsUntrackedWithIdentityResolutionSpec(int id) - { - Query.Where(product => product.Id == id).AsNoTrackingWithIdentityResolution(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdSpec.cs deleted file mode 100644 index 667c234d..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByIdSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class ProductByIdSpec : Specification -{ - public ProductByIdSpec(int id) - { - Query.Where(x => x.Id == id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByStoreIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByStoreIdSpec.cs deleted file mode 100644 index 339aeb3e..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/ProductByStoreIdSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class ProductByStoreIdSpec : Specification -{ - public ProductByStoreIdSpec(int storeId) - { - Query.Where(x => x.StoreId == storeId); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdAndNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdAndNameSpec.cs deleted file mode 100644 index febc3719..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdAndNameSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdAndNameSpec : Specification -{ - public StoreByIdAndNameSpec(int id, string name) - { - Query.Where(x => x.Id == id) - .Where(x => x.Name == name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressAndProductsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressAndProductsSpec.cs deleted file mode 100644 index 48f88a45..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressAndProductsSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdIncludeAddressAndProductsSpec : Specification, ISingleResultSpecification -{ - public StoreByIdIncludeAddressAndProductsSpec(int id) - { - Query.Where(x => x.Id == id); - Query.Include(x => x.Address); - Query.Include(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressSpec.cs deleted file mode 100644 index b3d2be23..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeAddressSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdIncludeAddressSpec : Specification, ISingleResultSpecification -{ - public StoreByIdIncludeAddressSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(x => x.Address); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec.cs deleted file mode 100644 index 767e4279..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec : Specification, ISingleResultSpecification -{ - public StoreByIdIncludeCompanyAndCountryAndStoresForCompanySpec(int id) - { - Query.Where(x => x.Id == id); - Query.Include(x => x.Company).ThenInclude(x => x!.Country); - Query.Include(x => x.Company).ThenInclude(x => x!.Stores).ThenInclude(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsSpec.cs deleted file mode 100644 index ecfe7995..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdIncludeProductsSpec : Specification, ISingleResultSpecification -{ - public StoreByIdIncludeProductsSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsUsingStringSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsUsingStringSpec.cs deleted file mode 100644 index befc9a81..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdIncludeProductsUsingStringSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdIncludeProductsUsingStringSpec : Specification, ISingleResultSpecification -{ - public StoreByIdIncludeProductsUsingStringSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(nameof(Store.Products)); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameAndCitySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameAndCitySpec.cs deleted file mode 100644 index b5875851..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameAndCitySpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdSearchByNameAndCitySpec : Specification -{ - public StoreByIdSearchByNameAndCitySpec(int id, string searchTerm) - { - Query.Where(x => x.Id == id) - .Search(x => x.Name!, "%" + searchTerm + "%", 1) - .Search(x => x.City!, "%" + searchTerm + "%", 2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameOrCitySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameOrCitySpec.cs deleted file mode 100644 index b9b50326..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSearchByNameOrCitySpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdSearchByNameOrCitySpec : Specification -{ - public StoreByIdSearchByNameOrCitySpec(int id, string searchTerm) - { - Query.Where(x => x.Id == id) - .Search(x => x.Name!, "%" + searchTerm + "%") - .Search(x => x.City!, "%" + searchTerm + "%"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSpec.cs deleted file mode 100644 index 4815d145..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreByIdSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreByIdSpec : Specification -{ - public StoreByIdSpec(int id) - { - Query.Where(x => x.Id == id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateSkipSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateSkipSpec.cs deleted file mode 100644 index 321a5658..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateSkipSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreDuplicateSkipSpec : Specification -{ - public StoreDuplicateSkipSpec() - { - Query.Skip(1) - .Skip(2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateTakeSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateTakeSpec.cs deleted file mode 100644 index 2f2e755c..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreDuplicateTakeSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreDuplicateTakeSpec : Specification -{ - public StoreDuplicateTakeSpec() - { - Query.Take(1) - .Take(2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreEmptySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreEmptySpec.cs deleted file mode 100644 index f6430750..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreEmptySpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreEmptySpec : Specification -{ - public StoreEmptySpec() - { - - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesEmptySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesEmptySpec.cs deleted file mode 100644 index 54568e4e..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesEmptySpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreNamesEmptySpec : Specification -{ - public StoreNamesEmptySpec() - { - - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesPaginatedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesPaginatedSpec.cs deleted file mode 100644 index cbccbb12..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesPaginatedSpec.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreNamesPaginatedSpec : Specification -{ - public StoreNamesPaginatedSpec(int skip, int take) - { - Query.OrderBy(x => x.Id) - .Skip(skip) - .Take(take); - - Query.Select(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesSpec.cs deleted file mode 100644 index df3972be..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreNamesSpec : Specification -{ - public StoreNamesSpec() - { - Query.Select(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesWithPostProcessingActionSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesWithPostProcessingActionSpec.cs deleted file mode 100644 index ec7e175b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreNamesWithPostProcessingActionSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreNamesWithPostProcessingActionSpec : Specification -{ - public StoreNamesWithPostProcessingActionSpec() - { - Query.Select(x => x.Name) - .PostProcessingAction(x => x); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesEmptySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesEmptySpec.cs deleted file mode 100644 index 95dad8be..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesEmptySpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreProductNamesEmptySpec : Specification -{ - public StoreProductNamesEmptySpec() - { - - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesSpec.cs deleted file mode 100644 index 9a342987..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreProductNamesSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreProductNamesSpec : Specification -{ - public StoreProductNamesSpec() - { - Query.SelectMany(s => s.Products.Select(p => p.Name)); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameAndCitySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameAndCitySpec.cs deleted file mode 100644 index 2b52eb71..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameAndCitySpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreSearchByNameAndCitySpec : Specification -{ - public StoreSearchByNameAndCitySpec(string searchTerm) - { - Query.Search(x => x.Name!, "%" + searchTerm + "%", 1) - .Search(x => x.City!, "%" + searchTerm + "%", 2); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameOrCitySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameOrCitySpec.cs deleted file mode 100644 index e2d9d4d7..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameOrCitySpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreSearchByNameOrCitySpec : Specification -{ - public StoreSearchByNameOrCitySpec(string searchTerm) - { - Query.Search(x => x.Name!, "%" + searchTerm + "%") - .Search(x => x.City!, "%" + searchTerm + "%"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameSpec.cs deleted file mode 100644 index 8f5e69d2..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreSearchByNameSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreSearchByNameSpec : Specification -{ - public StoreSearchByNameSpec(string searchTerm) - { - Query.Search(x => x.Name!, "%" + searchTerm + "%"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreWithPostProcessingActionSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreWithPostProcessingActionSpec.cs deleted file mode 100644 index 8649b60f..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoreWithPostProcessingActionSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreWithPostProcessingActionSpec : Specification -{ - public StoreWithPostProcessingActionSpec() - { - Query.PostProcessingAction(x => x); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameSpec.cs deleted file mode 100644 index 96def25b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByCompanyOrderedDescByNameSpec : Specification -{ - public StoresByCompanyOrderedDescByNameSpec(int companyId) - { - Query.Where(x => x.CompanyId == companyId) - .OrderByDescending(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByDescIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByDescIdSpec.cs deleted file mode 100644 index 6839be4d..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByDescIdSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByCompanyOrderedDescByNameThenByDescIdSpec : Specification -{ - public StoresByCompanyOrderedDescByNameThenByDescIdSpec(int companyId) - { - Query.Where(x => x.CompanyId == companyId) - .OrderByDescending(x => x.Name) - .ThenByDescending(x => x.Id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByIdSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByIdSpec.cs deleted file mode 100644 index d80d5ee7..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyOrderedDescByNameThenByIdSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByCompanyOrderedDescByNameThenByIdSpec : Specification -{ - public StoresByCompanyOrderedDescByNameThenByIdSpec(int companyId) - { - Query.Where(x => x.CompanyId == companyId) - .OrderByDescending(x => x.Name) - .ThenBy(x => x.Id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedOrderedDescByNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedOrderedDescByNameSpec.cs deleted file mode 100644 index 844aa480..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedOrderedDescByNameSpec.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByCompanyPaginatedOrderedDescByNameSpec : Specification -{ - public StoresByCompanyPaginatedOrderedDescByNameSpec(int companyId, int skip, int take) - { - Query.Where(x => x.CompanyId == companyId) - .Skip(skip) - .Take(take) - .OrderByDescending(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedSpec.cs deleted file mode 100644 index 1fca13cf..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByCompanyPaginatedSpec.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByCompanyPaginatedSpec : Specification -{ - public StoresByCompanyPaginatedSpec(int companyId, int skip, int take) - { - Query.Where(x => x.CompanyId == companyId) - .OrderBy(x => x.CompanyId) - .Skip(skip) - .Take(take); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByIdListSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByIdListSpec.cs deleted file mode 100644 index d7a0432c..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresByIdListSpec.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresByIdListSpec : Specification -{ - public StoresByIdListSpec(IEnumerable ids) - { - Query.Where(x => ids.Contains(x.Id)); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedDescendingByNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedDescendingByNameSpec.cs deleted file mode 100644 index 4c458706..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedDescendingByNameSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresOrderedDescendingByNameSpec : Specification -{ - public StoresOrderedDescendingByNameSpec() - { - Query.OrderByDescending(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedSpecByName.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedSpecByName.cs deleted file mode 100644 index f8822376..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedSpecByName.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresOrderedSpecByName : Specification -{ - public StoresOrderedSpecByName() - { - Query.OrderBy(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedTwoChainsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedTwoChainsSpec.cs deleted file mode 100644 index 49eefd34..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresOrderedTwoChainsSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresOrderedTwoChainsSpec : Specification -{ - public StoresOrderedTwoChainsSpec() - { - Query.OrderBy(x => x.Name) - .OrderBy(x => x.Id); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresPaginatedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresPaginatedSpec.cs deleted file mode 100644 index 57432b23..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/Specs/StoresPaginatedSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoresPaginatedSpec : Specification -{ - public StoresPaginatedSpec(int skip, int take) - { - Query.OrderBy(s => s.Id) - .Skip(skip) - .Take(take); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/CompanyIncludeFilteredStoresSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/CompanyIncludeFilteredStoresSpec.cs deleted file mode 100644 index e39dd17b..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/CompanyIncludeFilteredStoresSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class CompanyIncludeFilteredStoresSpec : Specification -{ - public CompanyIncludeFilteredStoresSpec(int id) - { - Query.Where(x => x.Id == id) - .Include(x => x.Stores.Where(s => s.Id == 1)); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressAndProductsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressAndProductsSpec.cs deleted file mode 100644 index 54ab0aec..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressAndProductsSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeAddressAndProductsSpec : Specification -{ - public StoreIncludeAddressAndProductsSpec() - { - Query.Include(x => x.Products) - .Include(x => x!.Address); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressSpec.cs deleted file mode 100644 index 7f38dcd8..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeAddressSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeAddressSpec : Specification -{ - public StoreIncludeAddressSpec() - { - Query.Include(x => x.Address); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyCountryDotSeparatedSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyCountryDotSeparatedSpec.cs deleted file mode 100644 index 61e3d00c..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyCountryDotSeparatedSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeCompanyCountryDotSeparatedSpec : Specification -{ - public StoreIncludeCompanyCountryDotSeparatedSpec() - { - Query.Include(x => x.Company!.Country); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountryAsStringSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountryAsStringSpec.cs deleted file mode 100644 index 788630a3..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountryAsStringSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeCompanyThenCountryAsStringSpec : Specification -{ - public StoreIncludeCompanyThenCountryAsStringSpec() - { - Query.Include($"{nameof(Company)}.{nameof(Company.Country)}"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountrySpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountrySpec.cs deleted file mode 100644 index 2dec8e07..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenCountrySpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeCompanyThenCountrySpec : Specification -{ - public StoreIncludeCompanyThenCountrySpec() - { - Query.Include(x => x.Company) - .ThenInclude(x => x!.Country); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenNameSpec.cs deleted file mode 100644 index 1787a365..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenNameSpec.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeCompanyThenNameSpec : Specification -{ - public StoreIncludeCompanyThenNameSpec() - { - Query.Include(x => x.Company) - .ThenInclude(x => x!.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenStoresSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenStoresSpec.cs deleted file mode 100644 index 3488b0f7..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeCompanyThenStoresSpec.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeCompanyThenStoresSpec : Specification -{ - public StoreIncludeCompanyThenStoresSpec() - { - Query.Include(x => x.Company) - .ThenInclude(x => x!.Stores) - .ThenInclude(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodOfNavigationSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodOfNavigationSpec.cs deleted file mode 100644 index 67dce23c..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodOfNavigationSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeMethodOfNavigationSpec : Specification -{ - public StoreIncludeMethodOfNavigationSpec() - { - Query.Include(x => x.Address!.GetSomethingFromAddress()); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodSpec.cs deleted file mode 100644 index 817270af..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeMethodSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeMethodSpec : Specification -{ - public StoreIncludeMethodSpec() - { - Query.Include(x => Store.GetSomethingFromStore()); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeNameSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeNameSpec.cs deleted file mode 100644 index 60dfaf7a..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeNameSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeNameSpec : Specification -{ - public StoreIncludeNameSpec() - { - Query.Include(x => x.Name); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeProductsSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeProductsSpec.cs deleted file mode 100644 index 841c889c..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreIncludeProductsSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreIncludeProductsSpec : Specification -{ - public StoreIncludeProductsSpec() - { - Query.Include(x => x.Products); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreWithFaultyIncludeSpec.cs b/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreWithFaultyIncludeSpec.cs deleted file mode 100644 index 51e092d1..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/Fixture/SpecsForIncludeTests/StoreWithFaultyIncludeSpec.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ardalis.Specification.UnitTests.Fixture.Specs; - -public class StoreWithFaultyIncludeSpec : Specification -{ - public StoreWithFaultyIncludeSpec() - { - Query.Include(x => x.Id == 1 && x.Name == "Something"); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/GlobalUsings.cs b/Specification/tests/Ardalis.Specification.UnitTests/GlobalUsings.cs deleted file mode 100644 index 9553d65e..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/GlobalUsings.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Ardalis.Specification.UnitTests.Fixture.Entities; -global using Ardalis.Specification.UnitTests.Fixture.Specs; -global using FluentAssertions; -global using System.Linq; -global using Xunit; diff --git a/Specification/tests/Ardalis.Specification.UnitTests/IncludeExpressionInfoTests.cs b/Specification/tests/Ardalis.Specification.UnitTests/IncludeExpressionInfoTests.cs deleted file mode 100644 index b45ef907..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/IncludeExpressionInfoTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Linq.Expressions; - -namespace Ardalis.Specification.UnitTests; - -public class IncludeExpressionInfoTests -{ - private readonly Expression> _expr; - - public IncludeExpressionInfoTests() - { - _expr = x => x.Country!; - } - - [Fact] - public void ThrowsArgumentNullException_GivenNullForLambdaExpression() - { - Action sutAction = () => new IncludeExpressionInfo(null!, typeof(Company), typeof(Country)); - - sutAction.Should() - .Throw(); - } - - [Fact] - public void ThrowsArgumentNullException_GivenNullForEntityType() - { - Action sutAction = () => new IncludeExpressionInfo(_expr, null!, typeof(Country)); - - sutAction.Should() - .Throw(); - } - - [Fact] - public void ThrowsArgumentNullException_GivenNullForPropertyType() - { - Action sutAction = () => new IncludeExpressionInfo(_expr, typeof(Company), null!); - - sutAction.Should() - .Throw(); - } - - [Fact] - public void ThrowsArgumentNullException_GivenNullForPreviousPropertyType() - { - Action sutAction = () => new IncludeExpressionInfo(_expr, typeof(Company), typeof(Country), null!); - - sutAction.Should() - .Throw(); - } -} diff --git a/Specification/tests/Ardalis.Specification.UnitTests/ValidatorTests/SpecificationValidator_Tests.cs b/Specification/tests/Ardalis.Specification.UnitTests/ValidatorTests/SpecificationValidator_Tests.cs deleted file mode 100644 index 4f6baadd..00000000 --- a/Specification/tests/Ardalis.Specification.UnitTests/ValidatorTests/SpecificationValidator_Tests.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Ardalis.Specification.UnitTests.Fixture.Entities.Seeds; - -namespace Ardalis.Specification.UnitTests.ValidatorTests; - -public class SpecificationValidator_Tests -{ - private readonly Store _store = StoreSeed.Get().Single(x => x.Id == StoreSeed.VALID_Search_ID); - - public void ReturnsTrue_GivenStoreByIdSearchByNameAndCitySpec_WithValidValues() - { - var spec = new StoreByIdSearchByNameAndCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_City_Name_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeTrue(); - } - - public void ReturnsFalse_GivenStoreByIdSearchByNameAndCitySpec_WithInvalidId() - { - var spec = new StoreByIdSearchByNameAndCitySpec(1, StoreSeed.VALID_Search_City_Name_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeFalse(); - } - - public void ReturnsFalse_GivenStoreByIdSearchByNameAndCitySpec_WithInvalidNameSearchString() - { - var spec = new StoreByIdSearchByNameAndCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_City_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeFalse(); - } - - public void ReturnsFalse_GivenStoreByIdSearchByNameAndCitySpec_WithInvalidCitySearchString() - { - var spec = new StoreByIdSearchByNameAndCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_Name_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeFalse(); - } - - public void ReturnsFalse_StoreByIdSearchByNameAndCitySpecSpec_WithInvalidCityAndNameSearchString() - { - var spec = new StoreByIdSearchByNameAndCitySpec(StoreSeed.VALID_Search_ID, "random"); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeFalse(); - } - - public void ReturnsTrue_StoreByIdSearchByNameOrCitySpecSpec_WithValidValues() - { - var spec = new StoreByIdSearchByNameOrCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_City_Name_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeTrue(); - } - - public void ReturnsTrue_StoreByIdSearchByNameOrCitySpecSpec_WithInvalidNameSearchString() - { - var spec = new StoreByIdSearchByNameOrCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_City_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeTrue(); - } - - public void ReturnsTrue_StoreByIdSearchByNameOrCitySpecSpec_WithInvalidCitySearchString() - { - var spec = new StoreByIdSearchByNameOrCitySpec(StoreSeed.VALID_Search_ID, StoreSeed.VALID_Search_Name_Key); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeTrue(); - } - - public void ReturnsFalse_StoreByIdSearchByNameOrCitySpecSpec_WithInvalidCityAndNameSearchString() - { - var spec = new StoreByIdSearchByNameOrCitySpec(StoreSeed.VALID_Search_ID, "random"); - - var result = spec.IsSatisfiedBy(_store); - - result.Should().BeFalse(); - } -} diff --git a/ci.slnf b/ci.slnf index a2c8d5f2..149169b2 100644 --- a/ci.slnf +++ b/ci.slnf @@ -3,11 +3,11 @@ "path": "Ardalis.Specification.sln", "projects": [ "Specification.EntityFramework6\\src\\Ardalis.Specification.EntityFramework6\\Ardalis.Specification.EntityFramework6.csproj", - "Specification.EntityFramework6\\tests\\Ardalis.Specification.EntityFramework6.IntegrationTests\\Ardalis.Specification.EntityFramework6.IntegrationTests.csproj", + "Specification.EntityFramework6\\tests\\Ardalis.Specification.EntityFramework6.Tests\\Ardalis.Specification.EntityFramework6.Tests.csproj", "Specification.EntityFrameworkCore\\src\\Ardalis.Specification.EntityFrameworkCore\\Ardalis.Specification.EntityFrameworkCore.csproj", - "Specification.EntityFrameworkCore\\tests\\Ardalis.Specification.EntityFrameworkCore.IntegrationTests\\Ardalis.Specification.EntityFrameworkCore.IntegrationTests.csproj", + "Specification.EntityFrameworkCore\\tests\\Ardalis.Specification.EntityFrameworkCore.Tests\\Ardalis.Specification.EntityFrameworkCore.Tests.csproj", "Specification\\src\\Ardalis.Specification\\Ardalis.Specification.csproj", - "Specification\\tests\\Ardalis.Specification.UnitTests\\Ardalis.Specification.UnitTests.csproj" + "Specification\\tests\\Ardalis.Specification.Tests\\Ardalis.Specification.Tests.csproj" ] } } \ No newline at end of file