using System.Linq; using System.Linq.Expressions; using MaksIT.Core.Extensions; namespace MaksIT.Core.Tests.Extensions; public class ExpressionExtensionsTests { [Fact] public void AndAlso_ShouldCombineTwoPredicatesWithAndCondition() { // Arrange Expression> firstPredicate = x => x.Age > 18; Expression> secondPredicate = x => (x.Name ?? "").StartsWith("A"); // Act var combinedPredicate = firstPredicate.AndAlso(secondPredicate); var compiledPredicate = combinedPredicate.Compile(); // Assert Assert.True(compiledPredicate(new TestEntity { Age = 20, Name = "Alice" })); Assert.False(compiledPredicate(new TestEntity { Age = 17, Name = "Alice" })); Assert.False(compiledPredicate(new TestEntity { Age = 20, Name = "Bob" })); } /// /// Ensures AndAlso produces an expression that works with IQueryable.Where (as used by EF Core). /// [Fact] public void AndAlso_ShouldWorkWithIQueryableWhere() { var source = new List { new() { Age = 20, Name = "Alice" }, new() { Age = 17, Name = "Alice" }, new() { Age = 20, Name = "Bob" }, new() { Age = 25, Name = "Amy" } }; Expression> first = x => x.Age > 18; Expression> second = x => (x.Name ?? "").StartsWith("A"); var combined = first.AndAlso(second); var result = source.AsQueryable().Where(combined).ToList(); Assert.Equal(2, result.Count); Assert.Contains(result, e => e.Name == "Alice" && e.Age == 20); Assert.Contains(result, e => e.Name == "Amy" && e.Age == 25); } [Fact] public void OrElse_ShouldCombineTwoPredicatesWithOrCondition() { // Arrange Expression> firstPredicate = x => x.Age > 18; Expression> secondPredicate = x => (x.Name ?? "").StartsWith("A"); // Act var combinedPredicate = firstPredicate.OrElse(secondPredicate); var compiledPredicate = combinedPredicate.Compile(); // Assert Assert.True(compiledPredicate(new TestEntity { Age = 20, Name = "Alice" })); Assert.True(compiledPredicate(new TestEntity { Age = 17, Name = "Alice" })); Assert.True(compiledPredicate(new TestEntity { Age = 20, Name = "Bob" })); Assert.False(compiledPredicate(new TestEntity { Age = 17, Name = "Bob" })); } [Fact] public void Not_ShouldNegatePredicate() { // Arrange Expression> predicate = x => x.Age > 18; // Act var negatedPredicate = predicate.Not(); var compiledPredicate = negatedPredicate.Compile(); // Assert Assert.False(compiledPredicate(new TestEntity { Age = 20 })); Assert.True(compiledPredicate(new TestEntity { Age = 17 })); } [Fact] public void AndAlso_ShouldHandleNullValues() { // Arrange Expression> firstPredicate = x => x.Name != null; Expression> secondPredicate = x => (x.Name ?? "").Length > 3; // Act var combinedPredicate = firstPredicate.AndAlso(secondPredicate); var compiledPredicate = combinedPredicate.Compile(); // Assert Assert.False(compiledPredicate(new TestEntity { Name = null })); Assert.True(compiledPredicate(new TestEntity { Name = "John" })); } [Fact] public void Not_ShouldThrowExceptionForNullExpression() { // Act & Assert Assert.Throws(() => ExpressionExtensions.Not(null!)); } [Fact] public void AndAlso_ShouldThrowExceptionForNullExpression() { // Arrange Expression> firstPredicate = null!; Expression> secondPredicate = x => x.Age > 18; // Act & Assert Assert.Throws(() => firstPredicate.AndAlso(secondPredicate)); } [Fact] public void OrElse_ShouldThrowExceptionForNullExpression() { // Arrange Expression> firstPredicate = x => x.Age > 18; Expression> secondPredicate = null!; // Act & Assert Assert.Throws(() => firstPredicate.OrElse(secondPredicate)); } [Fact] public void Batch_ShouldDivideCollectionIntoBatchesOfGivenSize() { // Arrange var source = Enumerable.Range(1, 10); int batchSize = 3; // Act var batches = source.Batch(batchSize).ToList(); // Assert Assert.Equal(4, batches.Count); Assert.Equal(new List { 1, 2, 3 }, batches[0]); Assert.Equal(new List { 4, 5, 6 }, batches[1]); Assert.Equal(new List { 7, 8, 9 }, batches[2]); Assert.Equal(new List { 10 }, batches[3]); } private class TestEntity { public Guid Id { get; set; } public int Age { get; set; } public string? Name { get; set; } } }