sprints enhancements
This commit is contained in:
@@ -65,14 +65,14 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
PolicyDslArbs.ValidPolicyName(),
|
||||
name =>
|
||||
{
|
||||
var source = $"""
|
||||
policy "{name}" syntax "stella-dsl@1" {{
|
||||
rule test priority 1 {{
|
||||
var source = $$"""
|
||||
policy "{{name}}" syntax "stella-dsl@1" {
|
||||
rule test priority 1 {
|
||||
when true
|
||||
then severity := "low"
|
||||
because "test"
|
||||
}}
|
||||
}}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var result1 = _compiler.Compile(source);
|
||||
@@ -179,6 +179,102 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Score-based conditions roundtrip correctly.
|
||||
/// </summary>
|
||||
[Property(MaxTest = 50)]
|
||||
public Property ScoreConditions_RoundtripCorrectly()
|
||||
{
|
||||
return Prop.ForAll(
|
||||
PolicyDslArbs.ValidPolicyWithScoreConditions(),
|
||||
source =>
|
||||
{
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Score policy doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
var result2 = _compiler.Compile(printed);
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label($"Score policy roundtrip failed: {string.Join("; ", result2.Diagnostics.Select(d => d.Message))}");
|
||||
}
|
||||
|
||||
return AreDocumentsEquivalent(result1.Document, result2.Document)
|
||||
.Label("Score policy documents should be equivalent after roundtrip");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Each score condition type parses successfully.
|
||||
/// </summary>
|
||||
[Property(MaxTest = 50)]
|
||||
public Property IndividualScoreConditions_ParseSuccessfully()
|
||||
{
|
||||
return Prop.ForAll(
|
||||
PolicyDslArbs.ScoreCondition(),
|
||||
condition =>
|
||||
{
|
||||
var source = $$"""
|
||||
policy "ScoreTest" syntax "stella-dsl@1" {
|
||||
rule test priority 1 {
|
||||
when {{condition}}
|
||||
then severity := "high"
|
||||
because "Score condition test"
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var result = _compiler.Compile(source);
|
||||
|
||||
return (result.Success && result.Document is not null)
|
||||
.Label($"Score condition '{condition}' should parse successfully");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Score expression structure preserved through roundtrip.
|
||||
/// </summary>
|
||||
[Property(MaxTest = 50)]
|
||||
public Property ScoreExpressionStructure_PreservedThroughRoundtrip()
|
||||
{
|
||||
return Prop.ForAll(
|
||||
PolicyDslArbs.ScoreCondition(),
|
||||
condition =>
|
||||
{
|
||||
var source = $$"""
|
||||
policy "ScoreTest" syntax "stella-dsl@1" {
|
||||
rule test priority 1 {
|
||||
when {{condition}}
|
||||
then severity := "high"
|
||||
because "Score test"
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label($"Skip: Condition '{condition}' doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
var result2 = _compiler.Compile(printed);
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label($"Roundtrip failed for '{condition}'");
|
||||
}
|
||||
|
||||
// Verify rule count matches
|
||||
return (result1.Document.Rules.Length == result2.Document.Rules.Length)
|
||||
.Label($"Rule count preserved for condition '{condition}'");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property: Different policies produce different checksums.
|
||||
/// </summary>
|
||||
@@ -256,6 +352,29 @@ internal static class PolicyDslArbs
|
||||
"status == \"blocked\""
|
||||
];
|
||||
|
||||
// Sprint 8200.0012.0003: Score-based conditions for EWS integration
|
||||
private static readonly string[] ScoreConditions =
|
||||
[
|
||||
"score >= 70",
|
||||
"score > 80",
|
||||
"score <= 50",
|
||||
"score < 40",
|
||||
"score == 75",
|
||||
"score.is_act_now",
|
||||
"score.is_schedule_next",
|
||||
"score.is_investigate",
|
||||
"score.is_watchlist",
|
||||
"score.bucket == \"ActNow\"",
|
||||
"score.rch > 0.8",
|
||||
"score.xpl > 0.7",
|
||||
"score.has_flag(\"kev\")",
|
||||
"score.has_flag(\"live-signal\")",
|
||||
"score.between(60, 80)",
|
||||
"score >= 70 and score.is_schedule_next",
|
||||
"score > 80 or score.has_flag(\"kev\")",
|
||||
"score.rch > 0.8 and score.xpl > 0.7"
|
||||
];
|
||||
|
||||
private static readonly string[] ValidActions =
|
||||
[
|
||||
"severity := \"info\"",
|
||||
@@ -296,6 +415,22 @@ internal static class PolicyDslArbs
|
||||
from rules in Gen.ArrayOf(1, GenRule())
|
||||
select BuildPolicyWithMetadata(name, hasVersion, hasAuthor, rules));
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Generates policies with score-based conditions.
|
||||
/// </summary>
|
||||
public static Arbitrary<string> ValidPolicyWithScoreConditions() =>
|
||||
Arb.From(
|
||||
from name in Gen.Elements(ValidIdentifiers)
|
||||
from ruleCount in Gen.Choose(1, 3)
|
||||
from rules in Gen.ArrayOf(ruleCount, GenScoreRule())
|
||||
select BuildPolicy(name, rules));
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Generates a specific score condition for targeted testing.
|
||||
/// </summary>
|
||||
public static Arbitrary<string> ScoreCondition() =>
|
||||
Arb.From(Gen.Elements(ScoreConditions));
|
||||
|
||||
private static Gen<string> GenRule()
|
||||
{
|
||||
return from nameIndex in Gen.Choose(0, ValidIdentifiers.Length - 1)
|
||||
@@ -306,22 +441,44 @@ internal static class PolicyDslArbs
|
||||
let priority = ValidPriorities[priorityIndex]
|
||||
let condition = ValidConditions[conditionIndex]
|
||||
let action = ValidActions[actionIndex]
|
||||
select $"""
|
||||
rule {name} priority {priority} {{
|
||||
when {condition}
|
||||
then {action}
|
||||
select $$"""
|
||||
rule {{name}} priority {{priority}} {
|
||||
when {{condition}}
|
||||
then {{action}}
|
||||
because "Generated test rule"
|
||||
}}
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sprint 8200.0012.0003: Generates rules with score-based conditions.
|
||||
/// </summary>
|
||||
private static Gen<string> GenScoreRule()
|
||||
{
|
||||
return from nameIndex in Gen.Choose(0, ValidIdentifiers.Length - 1)
|
||||
from priorityIndex in Gen.Choose(0, ValidPriorities.Length - 1)
|
||||
from conditionIndex in Gen.Choose(0, ScoreConditions.Length - 1)
|
||||
from actionIndex in Gen.Choose(0, ValidActions.Length - 1)
|
||||
let name = ValidIdentifiers[nameIndex]
|
||||
let priority = ValidPriorities[priorityIndex]
|
||||
let condition = ScoreConditions[conditionIndex]
|
||||
let action = ValidActions[actionIndex]
|
||||
select $$"""
|
||||
rule {{name}} priority {{priority}} {
|
||||
when {{condition}}
|
||||
then {{action}}
|
||||
because "Score-based rule"
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
private static string BuildPolicy(string name, string[] rules)
|
||||
{
|
||||
var rulesText = string.Join("\n", rules);
|
||||
return $"""
|
||||
policy "{name}" syntax "stella-dsl@1" {{
|
||||
{rulesText}
|
||||
}}
|
||||
return $$"""
|
||||
policy "{{name}}" syntax "stella-dsl@1" {
|
||||
{{rulesText}}
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@@ -332,20 +489,20 @@ internal static class PolicyDslArbs
|
||||
if (hasAuthor) metadataLines.Add(" author = \"test\"");
|
||||
|
||||
var metadata = metadataLines.Count > 0
|
||||
? $"""
|
||||
metadata {{
|
||||
{string.Join("\n", metadataLines)}
|
||||
}}
|
||||
? $$"""
|
||||
metadata {
|
||||
{{string.Join("\n", metadataLines)}}
|
||||
}
|
||||
"""
|
||||
: "";
|
||||
|
||||
var rulesText = string.Join("\n", rules);
|
||||
|
||||
return $"""
|
||||
policy "{name}" syntax "stella-dsl@1" {{
|
||||
{metadata}
|
||||
{rulesText}
|
||||
}}
|
||||
return $$"""
|
||||
policy "{{name}}" syntax "stella-dsl@1" {
|
||||
{{metadata}}
|
||||
{{rulesText}}
|
||||
}
|
||||
""";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user