681 lines
23 KiB
C#
681 lines
23 KiB
C#
using Strata.SqlTools.Rules.Rule;
|
|
using Strata.SqlTools.Rules.Rule.Expression;
|
|
using GroupAnd = Strata.SqlTools.Rules.Rule.Groups.And;
|
|
using GroupOr = Strata.SqlTools.Rules.Rule.Groups.Or;
|
|
|
|
namespace Strata.SqlTools.Rules.Tests;
|
|
|
|
/// <summary>
|
|
/// Comprehensive unit tests for Strata.Rules based on Microsoft RulesEngine examples.
|
|
/// These tests demonstrate basic rule creation, evaluation, and various expression types.
|
|
/// </summary>
|
|
[TestFixture]
|
|
public class RuleEngineTests
|
|
{
|
|
#region BasicComparison Tests
|
|
|
|
[Test]
|
|
public async Task BasicEqualityRule_WithMatchingValue_ReturnsTrue()
|
|
{
|
|
// Arrange - Create a simple rule: input.country == "india"
|
|
var inputParam = new Parameter("input");
|
|
var countryProperty = inputParam.Property("country");
|
|
var expression = countryProperty == "india";
|
|
|
|
var rule = new SingleRule("CheckCountryIsIndia", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "india" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task BasicEqualityRule_WithNonMatchingValue_ReturnsFalse()
|
|
{
|
|
// Arrange - Create a simple rule: input.country == "india"
|
|
var inputParam = new Parameter("input");
|
|
var countryProperty = inputParam.Property("country");
|
|
var expression = countryProperty == "india";
|
|
|
|
var rule = new SingleRule("CheckCountryIsIndia", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "usa" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public async Task BasicNotEqualRule_WithDifferentValue_ReturnsTrue()
|
|
{
|
|
// Arrange - Create a simple rule: input.country != "india"
|
|
var inputParam = new Parameter("input");
|
|
var countryProperty = inputParam.Property("country");
|
|
var expression = countryProperty != "india";
|
|
|
|
var rule = new SingleRule("CheckCountryIsNotIndia", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "usa" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task BasicGreaterThanRule_WithHigherValue_ReturnsTrue()
|
|
{
|
|
// Arrange - Create a simple rule: input.totalPurchases > 5000
|
|
var inputParam = new Parameter("input");
|
|
var totalProperty = inputParam.Property("totalPurchases");
|
|
var expression = new GreaterThan(totalProperty, 5000m);
|
|
|
|
var rule = new SingleRule("CheckMinimumPurchase", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { totalPurchases = 10000m };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task BasicGreaterThanRule_WithLowerValue_ReturnsFalse()
|
|
{
|
|
// Arrange - Create a simple rule: input.totalPurchases > 5000
|
|
var inputParam = new Parameter("input");
|
|
var totalProperty = inputParam.Property("totalPurchases");
|
|
var expression = new GreaterThan(totalProperty, 5000m);
|
|
|
|
var rule = new SingleRule("CheckMinimumPurchase", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { totalPurchases = 3000m };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Logical Operator Tests
|
|
|
|
[Test]
|
|
public async Task And_WithBothConditionsTrue_ReturnsTrue()
|
|
{
|
|
// Arrange - Rule: input.country == "india" AND input.loyaltyFactor > 2
|
|
var inputParam = new Parameter("input");
|
|
var countryExpr = inputParam.Property("country") == "india";
|
|
var loyaltyExpr = new GreaterThan(inputParam.Property("loyaltyFactor"), 2m);
|
|
var expression = countryExpr & loyaltyExpr;
|
|
|
|
var rule = new SingleRule("CheckIndiaWithHighLoyalty", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "india", loyaltyFactor = 3m };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task And_WithOneConditionFalse_ReturnsFalse()
|
|
{
|
|
// Arrange - Rule: input.country == "india" AND input.loyaltyFactor > 2
|
|
var inputParam = new Parameter("input");
|
|
var countryExpr = inputParam.Property("country") == "india";
|
|
var loyaltyExpr = new GreaterThan(inputParam.Property("loyaltyFactor"), 2m);
|
|
var expression = countryExpr & loyaltyExpr;
|
|
|
|
var rule = new SingleRule("CheckIndiaWithHighLoyalty", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "india", loyaltyFactor = 1m };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Or_WithOneConditionTrue_ReturnsTrue()
|
|
{
|
|
// Arrange - Rule: input.country == "india" OR input.country == "usa"
|
|
var inputParam = new Parameter("input");
|
|
var indiaExpr = inputParam.Property("country") == "india";
|
|
var usaExpr = inputParam.Property("country") == "usa";
|
|
var expression = indiaExpr | usaExpr;
|
|
|
|
var rule = new SingleRule("CheckIndiaOrUsa", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "usa" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Or_WithBothConditionsFalse_ReturnsFalse()
|
|
{
|
|
// Arrange - Rule: input.country == "india" OR input.country == "usa"
|
|
var inputParam = new Parameter("input");
|
|
var indiaExpr = inputParam.Property("country") == "india";
|
|
var usaExpr = inputParam.Property("country") == "usa";
|
|
var expression = indiaExpr | usaExpr;
|
|
|
|
var rule = new SingleRule("CheckIndiaOrUsa", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "canada" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public async Task ComplexLogicalExpression_WithMixedOperators_EvaluatesCorrectly()
|
|
{
|
|
// Arrange - Rule: (input.country == "india" AND input.loyaltyFactor >= 2) OR input.vipCustomer == true
|
|
var inputParam = new Parameter("input");
|
|
var countryExpr = inputParam.Property("country") == "india";
|
|
var loyaltyExpr = new GreaterThan(inputParam.Property("loyaltyFactor"), 1m);
|
|
var vipExpr = inputParam.Property("vipCustomer") == "true";
|
|
|
|
var And = countryExpr & loyaltyExpr;
|
|
var expression = And | vipExpr;
|
|
|
|
var rule = new SingleRule("CheckEligibleCustomer", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "usa", loyaltyFactor = 1m, vipCustomer = "true" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True, "Should return true because vipCustomer is true");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Multiple Property Access Tests
|
|
|
|
[Test]
|
|
public async Task MultipleProperties_AllConditionsMet_ReturnsTrue()
|
|
{
|
|
// Arrange - Similar to RulesEngine discount example
|
|
// Rule: country == "india" AND totalPurchases >= 5000 AND totalOrders > 2
|
|
var inputParam = new Parameter("input");
|
|
var expression =
|
|
(inputParam.Property("country") == "india") &
|
|
new GreaterThan(inputParam.Property("totalPurchases"), 4999m) &
|
|
new GreaterThan(inputParam.Property("totalOrders"), 2m);
|
|
|
|
var rule = new SingleRule("GiveDiscount10", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
totalPurchases = 5000m,
|
|
totalOrders = 3m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task MultipleProperties_OneConditionNotMet_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var inputParam = new Parameter("input");
|
|
var expression =
|
|
(inputParam.Property("country") == "india") &
|
|
new GreaterThan(inputParam.Property("totalPurchases"), 4999m) &
|
|
new GreaterThan(inputParam.Property("totalOrders"), 2m);
|
|
|
|
var rule = new SingleRule("GiveDiscount10", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
totalPurchases = 5000m,
|
|
totalOrders = 1m // This condition fails
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Rule Group Tests
|
|
|
|
[Test]
|
|
public async Task AndRuleGroup_AllRulesPass_ReturnsTrue()
|
|
{
|
|
// Arrange - Create multiple rules that must all pass
|
|
var inputParam = new Parameter("input");
|
|
|
|
var rule1 = new SingleRule("CheckCountry", inputParam.Property("country") == "india");
|
|
var rule2 = new SingleRule("CheckLoyalty", new GreaterThan(inputParam.Property("loyaltyFactor"), 2m));
|
|
var rule3 = new SingleRule("CheckPurchases", new GreaterThan(inputParam.Property("totalPurchases"), 5000m));
|
|
|
|
var andGroup = new GroupAnd(new IRule[] { rule1, rule2, rule3 });
|
|
var ruleSet = new RuleSet(andGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
loyaltyFactor = 3m,
|
|
totalPurchases = 10000m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task AndRuleGroup_OneRuleFails_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var inputParam = new Parameter("input");
|
|
|
|
var rule1 = new SingleRule("CheckCountry", inputParam.Property("country") == "india");
|
|
var rule2 = new SingleRule("CheckLoyalty", new GreaterThan(inputParam.Property("loyaltyFactor"), 2m));
|
|
var rule3 = new SingleRule("CheckPurchases", new GreaterThan(inputParam.Property("totalPurchases"), 5000m));
|
|
|
|
var andGroup = new GroupAnd(new IRule[] { rule1, rule2, rule3 });
|
|
var ruleSet = new RuleSet(andGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
loyaltyFactor = 1m, // This rule fails
|
|
totalPurchases = 10000m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public async Task OrRuleGroup_OneRulePasses_ReturnsTrue()
|
|
{
|
|
// Arrange - At least one rule must pass
|
|
var inputParam = new Parameter("input");
|
|
|
|
var rule1 = new SingleRule("CheckIndia", inputParam.Property("country") == "india");
|
|
var rule2 = new SingleRule("CheckUSA", inputParam.Property("country") == "usa");
|
|
var rule3 = new SingleRule("CheckCanada", inputParam.Property("country") == "canada");
|
|
|
|
var orGroup = new GroupOr(new IRule[] { rule1, rule2, rule3 });
|
|
var ruleSet = new RuleSet(orGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "usa" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task OrRuleGroup_AllRulesFail_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var inputParam = new Parameter("input");
|
|
|
|
var rule1 = new SingleRule("CheckIndia", inputParam.Property("country") == "india");
|
|
var rule2 = new SingleRule("CheckUSA", inputParam.Property("country") == "usa");
|
|
var rule3 = new SingleRule("CheckCanada", inputParam.Property("country") == "canada");
|
|
|
|
var orGroup = new GroupOr(new IRule[] { rule1, rule2, rule3 });
|
|
var ruleSet = new RuleSet(orGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { country = "france" };
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.False);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Discount Calculation Example (Based on RulesEngine Documentation)
|
|
|
|
[Test]
|
|
public async Task DiscountRule_10Percent_AllConditionsMet_ReturnsTrue()
|
|
{
|
|
// Arrange - Simulates the RulesEngine discount example
|
|
// Rule: country == "india" AND loyaltyFactor <= 2 AND totalPurchases >= 5000 AND totalOrders > 2
|
|
var inputParam = new Parameter("input");
|
|
var expression =
|
|
(inputParam.Property("country") == "india") &
|
|
(inputParam.Property("loyaltyFactor") == 2m) & // <= 2
|
|
new GreaterThan(inputParam.Property("totalPurchasesToDate"), 4999m) & // >= 5000
|
|
new GreaterThan(inputParam.Property("totalOrders"), 2m);
|
|
|
|
var rule = new SingleRule("GiveDiscount10", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
loyaltyFactor = 2m,
|
|
totalPurchasesToDate = 5000m,
|
|
totalOrders = 3m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DiscountRule_20Percent_HigherLoyalty_ReturnsTrue()
|
|
{
|
|
// Arrange
|
|
// Rule: country == "india" AND loyaltyFactor == 3 AND totalPurchases >= 10000
|
|
var inputParam = new Parameter("input");
|
|
var expression =
|
|
(inputParam.Property("country") == "india") &
|
|
(inputParam.Property("loyaltyFactor") == 3m) &
|
|
new GreaterThan(inputParam.Property("totalPurchasesToDate"), 9999m);
|
|
|
|
var rule = new SingleRule("GiveDiscount20", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
loyaltyFactor = 3m,
|
|
totalPurchasesToDate = 10000m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task MultipleDiscountRules_OnlyOneMatches_UsesOrGroup()
|
|
{
|
|
// Arrange - Either 10% or 20% discount can apply
|
|
var inputParam = new Parameter("input");
|
|
|
|
var discount10 = new SingleRule("GiveDiscount10",
|
|
(inputParam.Property("country") == "india") &
|
|
(inputParam.Property("loyaltyFactor") == 2m) &
|
|
new GreaterThan(inputParam.Property("totalPurchases"), 4999m));
|
|
|
|
var discount20 = new SingleRule("GiveDiscount20",
|
|
(inputParam.Property("country") == "india") &
|
|
(inputParam.Property("loyaltyFactor") == 3m) &
|
|
new GreaterThan(inputParam.Property("totalPurchases"), 9999m));
|
|
|
|
var orGroup = new GroupOr(new IRule[] { discount10, discount20 });
|
|
var ruleSet = new RuleSet(orGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
country = "india",
|
|
loyaltyFactor = 3m,
|
|
totalPurchases = 15000m
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True, "Should match the 20% discount rule");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region String Operations
|
|
|
|
[Test]
|
|
public async Task StringComparison_CaseSensitive_WorksCorrectly()
|
|
{
|
|
// Arrange
|
|
var inputParam = new Parameter("input");
|
|
var expression = inputParam.Property("status") == "Active";
|
|
|
|
var rule = new SingleRule("CheckActiveStatus", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
|
|
// Act & Assert - Matching case
|
|
var result1 = await engine.RunRules(ruleSet, new { status = "Active" });
|
|
Assert.That(result1, Is.True);
|
|
|
|
// Act & Assert - Different case (should fail)
|
|
var result2 = await engine.RunRules(ruleSet, new { status = "active" });
|
|
Assert.That(result2, Is.False);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested Properties
|
|
|
|
[Test]
|
|
public async Task NestedProperty_Access_WorksCorrectly()
|
|
{
|
|
// Arrange - Access nested object properties
|
|
var inputParam = new Parameter("input");
|
|
var customerProperty = inputParam.Property("customer");
|
|
var expression = new Property(customerProperty, "country") == "india";
|
|
|
|
var rule = new SingleRule("CheckCustomerCountry", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
customer = new { country = "india", name = "John" }
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeepNestedProperty_MultipleLevel_WorksCorrectly()
|
|
{
|
|
// Arrange - Access deeply nested properties
|
|
var inputParam = new Parameter("input");
|
|
var orderProperty = inputParam.Property("order");
|
|
var customerProperty = new Property(orderProperty, "customer");
|
|
var addressProperty = new Property(customerProperty, "address");
|
|
var expression = new Property(addressProperty, "country") == "india";
|
|
|
|
var rule = new SingleRule("CheckOrderCustomerCountry", expression);
|
|
var ruleSet = new RuleSet(new GroupAnd(new[] { rule }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new
|
|
{
|
|
order = new
|
|
{
|
|
customer = new
|
|
{
|
|
address = new { country = "india", city = "Mumbai" }
|
|
}
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var result = await engine.RunRules(ruleSet, input);
|
|
|
|
// Assert
|
|
Assert.That(result, Is.True);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RuleSet Isolation Tests
|
|
|
|
[Test]
|
|
public async Task MultipleRuleSets_EvaluatedIndependently()
|
|
{
|
|
// Arrange - Two separate rule sets
|
|
var inputParam = new Parameter("input");
|
|
|
|
var rule1 = new SingleRule("Rule1", new GreaterThan(inputParam.Property("value"), 100m));
|
|
var ruleSet1 = new RuleSet(new GroupAnd(new[] { rule1 }), Guid.NewGuid());
|
|
|
|
var rule2 = new SingleRule("Rule2", inputParam.Property("value") == 50m);
|
|
var ruleSet2 = new RuleSet(new GroupAnd(new[] { rule2 }), Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
var input = new { value = 50m };
|
|
|
|
// Act
|
|
var result1 = await engine.RunRules(ruleSet1, input);
|
|
var result2 = await engine.RunRules(ruleSet2, input);
|
|
|
|
// Assert
|
|
Assert.That(result1, Is.False, "First rule set should fail");
|
|
Assert.That(result2, Is.True, "Second rule set should pass");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Complex Real-World Scenario
|
|
|
|
[Test]
|
|
public async Task ComplexBusinessRule_EligibilityCheck_EvaluatesCorrectly()
|
|
{
|
|
// Arrange - Complex eligibility rule inspired by RulesEngine examples
|
|
// Eligible if: (Premium member) OR (Regular member with good history)
|
|
var inputParam = new Parameter("input");
|
|
|
|
var premiumRule = new SingleRule("PremiumMember",
|
|
inputParam.Property("membershipType") == "Premium");
|
|
|
|
var regularWithHistoryExpr =
|
|
(inputParam.Property("membershipType") == "Regular") &
|
|
new GreaterThan(inputParam.Property("accountAge"), 365m) &
|
|
new GreaterThan(inputParam.Property("totalSpent"), 1000m) &
|
|
(inputParam.Property("negativeReviews") == 0m);
|
|
|
|
var regularRule = new SingleRule("RegularMemberGoodHistory", regularWithHistoryExpr);
|
|
|
|
var eligibilityGroup = new GroupOr(new IRule[] { premiumRule, regularRule });
|
|
var ruleSet = new RuleSet(eligibilityGroup, Guid.NewGuid());
|
|
|
|
var engine = new RuleSetEngine();
|
|
|
|
// Act & Assert - Premium member should be eligible
|
|
var premiumInput = new
|
|
{
|
|
membershipType = "Premium",
|
|
accountAge = 30m,
|
|
totalSpent = 100m,
|
|
negativeReviews = 5m
|
|
};
|
|
var premiumResult = await engine.RunRules(ruleSet, premiumInput);
|
|
Assert.That(premiumResult, Is.True, "Premium member should be eligible");
|
|
|
|
// Act & Assert - Regular member with good history should be eligible
|
|
var regularGoodInput = new
|
|
{
|
|
membershipType = "Regular",
|
|
accountAge = 400m,
|
|
totalSpent = 2000m,
|
|
negativeReviews = 0m
|
|
};
|
|
var regularGoodResult = await engine.RunRules(ruleSet, regularGoodInput);
|
|
Assert.That(regularGoodResult, Is.True, "Regular member with good history should be eligible");
|
|
|
|
// Act & Assert - Regular member with bad history should not be eligible
|
|
var regularBadInput = new
|
|
{
|
|
membershipType = "Regular",
|
|
accountAge = 400m,
|
|
totalSpent = 2000m,
|
|
negativeReviews = 3m
|
|
};
|
|
var regularBadResult = await engine.RunRules(ruleSet, regularBadInput);
|
|
Assert.That(regularBadResult, Is.False, "Regular member with negative reviews should not be eligible");
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|