Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
using FluentAssertions;
|
||||
using FsCheck;
|
||||
using FsCheck.Fluent;
|
||||
using FsCheck.Xunit;
|
||||
using StellaOps.PolicyDsl;
|
||||
using Xunit;
|
||||
@@ -32,7 +33,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Source doesn't parse cleanly");
|
||||
return true.ToProperty().Label("Skip: Source doesn't parse cleanly");
|
||||
}
|
||||
|
||||
// Print the document back to source
|
||||
@@ -44,14 +45,14 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
// Both should succeed
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label($"Roundtrip failed: {string.Join("; ", result2.Diagnostics.Select(d => d.Message))}");
|
||||
return false.ToProperty().Label($"Roundtrip failed: {string.Join("; ", result2.Diagnostics.Select(d => d.Message))}");
|
||||
}
|
||||
|
||||
// Documents should be semantically equivalent
|
||||
var equivalent = AreDocumentsEquivalent(result1.Document, result2.Document);
|
||||
|
||||
return equivalent
|
||||
.Label($"Documents should be equivalent after roundtrip");
|
||||
.ToProperty().Label($"Documents should be equivalent after roundtrip");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Name causes parse failure");
|
||||
return true.ToProperty().Label("Skip: Name causes parse failure");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
@@ -86,11 +87,11 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label("Roundtrip parse failed");
|
||||
return false.ToProperty().Label("Roundtrip parse failed");
|
||||
}
|
||||
|
||||
return (result1.Document.Name == result2.Document.Name)
|
||||
.Label($"Name should be preserved: '{result1.Document.Name}' vs '{result2.Document.Name}'");
|
||||
.ToProperty().Label($"Name should be preserved: '{result1.Document.Name}' vs '{result2.Document.Name}'");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Source doesn't parse");
|
||||
return true.ToProperty().Label("Skip: Source doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
@@ -115,11 +116,11 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label("Roundtrip parse failed");
|
||||
return false.ToProperty().Label("Roundtrip parse failed");
|
||||
}
|
||||
|
||||
return (result1.Document.Rules.Length == result2.Document.Rules.Length)
|
||||
.Label($"Rule count should be preserved: {result1.Document.Rules.Length} vs {result2.Document.Rules.Length}");
|
||||
.ToProperty().Label($"Rule count should be preserved: {result1.Document.Rules.Length} vs {result2.Document.Rules.Length}");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Source doesn't parse");
|
||||
return true.ToProperty().Label("Skip: Source doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
@@ -144,7 +145,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label("Roundtrip parse failed");
|
||||
return false.ToProperty().Label("Roundtrip parse failed");
|
||||
}
|
||||
|
||||
var keysMatch = result1.Document.Metadata.Keys
|
||||
@@ -152,7 +153,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
.SequenceEqual(result2.Document.Metadata.Keys.OrderBy(k => k));
|
||||
|
||||
return keysMatch
|
||||
.Label($"Metadata keys should be preserved");
|
||||
.ToProperty().Label($"Metadata keys should be preserved");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -171,11 +172,11 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result1.Success || !result2.Success)
|
||||
{
|
||||
return true.Label("Skip: Parse failures");
|
||||
return true.ToProperty().Label("Skip: Parse failures");
|
||||
}
|
||||
|
||||
return (result1.Checksum == result2.Checksum)
|
||||
.Label($"Checksum should be stable: {result1.Checksum} vs {result2.Checksum}");
|
||||
.ToProperty().Label($"Checksum should be stable: {result1.Checksum} vs {result2.Checksum}");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label("Skip: Score policy doesn't parse");
|
||||
return true.ToProperty().Label("Skip: Score policy doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
@@ -200,11 +201,11 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label($"Score policy roundtrip failed: {string.Join("; ", result2.Diagnostics.Select(d => d.Message))}");
|
||||
return false.ToProperty().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");
|
||||
.ToProperty().Label("Score policy documents should be equivalent after roundtrip");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,7 +232,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result = _compiler.Compile(source);
|
||||
|
||||
return (result.Success && result.Document is not null)
|
||||
.Label($"Score condition '{condition}' should parse successfully");
|
||||
.ToProperty().Label($"Score condition '{condition}' should parse successfully");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,7 +259,7 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
var result1 = _compiler.Compile(source);
|
||||
if (!result1.Success || result1.Document is null)
|
||||
{
|
||||
return true.Label($"Skip: Condition '{condition}' doesn't parse");
|
||||
return true.ToProperty().Label($"Skip: Condition '{condition}' doesn't parse");
|
||||
}
|
||||
|
||||
var printed = PolicyIrPrinter.Print(result1.Document);
|
||||
@@ -266,12 +267,12 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result2.Success || result2.Document is null)
|
||||
{
|
||||
return false.Label($"Roundtrip failed for '{condition}'");
|
||||
return false.ToProperty().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}'");
|
||||
.ToProperty().Label($"Rule count preserved for condition '{condition}'");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -291,18 +292,18 @@ public sealed class PolicyDslRoundtripPropertyTests
|
||||
|
||||
if (!result1.Success || !result2.Success)
|
||||
{
|
||||
return true.Label("Skip: Parse failures");
|
||||
return true.ToProperty().Label("Skip: Parse failures");
|
||||
}
|
||||
|
||||
// If sources are identical, checksums should match
|
||||
if (source1 == source2)
|
||||
{
|
||||
return (result1.Checksum == result2.Checksum)
|
||||
.Label("Identical sources should have same checksum");
|
||||
.ToProperty().Label("Identical sources should have same checksum");
|
||||
}
|
||||
|
||||
// Different sources may produce different checksums (not guaranteed if semantically equal)
|
||||
return true.Label("Different sources checked");
|
||||
return true.ToProperty().Label("Different sources checked");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -397,22 +398,22 @@ internal static class PolicyDslArbs
|
||||
Arb.From(
|
||||
from name in Gen.Elements(ValidIdentifiers)
|
||||
from ruleCount in Gen.Choose(1, 3)
|
||||
from rules in Gen.ArrayOf(ruleCount, GenRule())
|
||||
from rules in Gen.ArrayOf<string>(GenRule(), ruleCount)
|
||||
select BuildPolicy(name, rules));
|
||||
|
||||
public static Arbitrary<string> ValidPolicyWithRules() =>
|
||||
Arb.From(
|
||||
from name in Gen.Elements(ValidIdentifiers)
|
||||
from ruleCount in Gen.Choose(1, 5)
|
||||
from rules in Gen.ArrayOf(ruleCount, GenRule())
|
||||
from rules in Gen.ArrayOf<string>(GenRule(), ruleCount)
|
||||
select BuildPolicy(name, rules));
|
||||
|
||||
public static Arbitrary<string> ValidPolicyWithMetadata() =>
|
||||
Arb.From(
|
||||
from name in Gen.Elements(ValidIdentifiers)
|
||||
from hasVersion in Arb.Generate<bool>()
|
||||
from hasAuthor in Arb.Generate<bool>()
|
||||
from rules in Gen.ArrayOf(1, GenRule())
|
||||
from hasVersion in ArbMap.Default.GeneratorFor<bool>()
|
||||
from hasAuthor in ArbMap.Default.GeneratorFor<bool>()
|
||||
from rules in Gen.ArrayOf<string>(GenRule(), 1)
|
||||
select BuildPolicyWithMetadata(name, hasVersion, hasAuthor, rules));
|
||||
|
||||
/// <summary>
|
||||
@@ -422,7 +423,7 @@ internal static class PolicyDslArbs
|
||||
Arb.From(
|
||||
from name in Gen.Elements(ValidIdentifiers)
|
||||
from ruleCount in Gen.Choose(1, 3)
|
||||
from rules in Gen.ArrayOf(ruleCount, GenScoreRule())
|
||||
from rules in Gen.ArrayOf<string>(GenScoreRule(), ruleCount)
|
||||
select BuildPolicy(name, rules));
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user