Add RestrictObligatory filter for response rewriting
Change-Id: I30a386ac48fa8dcbd0635b77fa6449c755f0cd59
diff --git a/ast/ast_test.go b/ast/ast_test.go
index 49fdbe3..3965f1d 100644
--- a/ast/ast_test.go
+++ b/ast/ast_test.go
@@ -851,3 +851,324 @@
assert.Equal(t, "original_foundry", term.Foundry)
assert.Equal(t, "original_layer", term.Layer)
}
+
+func TestRestrictToObligatory(t *testing.T) {
+ tests := []struct {
+ name string
+ node Node
+ foundry string
+ layer string
+ expected Node
+ }{
+ {
+ name: "Simple term - kept as is",
+ node: &Term{
+ Foundry: "old_foundry",
+ Key: "DET",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: &Term{
+ Foundry: "new_foundry",
+ Key: "DET",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ },
+ {
+ name: "AND group - kept as is",
+ node: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "old_foundry",
+ Key: "A",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "B",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "C",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: AndRelation,
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "new_foundry",
+ Key: "A",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "new_foundry",
+ Key: "B",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "new_foundry",
+ Key: "C",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: AndRelation,
+ },
+ },
+ {
+ name: "OR group - becomes nil",
+ node: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "old_foundry",
+ Key: "A",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "B",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: OrRelation,
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: nil,
+ },
+ {
+ name: "Mixed AND with nested OR - OR removed",
+ node: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "old_foundry",
+ Key: "A",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "B",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "old_foundry",
+ Key: "C",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "D",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: OrRelation,
+ },
+ &Term{
+ Foundry: "old_foundry",
+ Key: "E",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: AndRelation,
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "new_foundry",
+ Key: "A",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "new_foundry",
+ Key: "B",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ &Term{
+ Foundry: "new_foundry",
+ Key: "E",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ },
+ Relation: AndRelation,
+ },
+ },
+ {
+ name: "AND group with all OR operands - becomes nil",
+ node: &TermGroup{
+ Operands: []Node{
+ &TermGroup{
+ Operands: []Node{
+ &Term{Key: "A", Match: MatchEqual},
+ &Term{Key: "B", Match: MatchEqual},
+ },
+ Relation: OrRelation,
+ },
+ &TermGroup{
+ Operands: []Node{
+ &Term{Key: "C", Match: MatchEqual},
+ &Term{Key: "D", Match: MatchEqual},
+ },
+ Relation: OrRelation,
+ },
+ },
+ Relation: AndRelation,
+ },
+ foundry: "",
+ layer: "",
+ expected: nil,
+ },
+ {
+ name: "AND group with one operand after restriction - returns single operand",
+ node: &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "old_foundry",
+ Key: "A",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ &TermGroup{
+ Operands: []Node{
+ &Term{Key: "B", Match: MatchEqual},
+ &Term{Key: "C", Match: MatchEqual},
+ },
+ Relation: OrRelation,
+ },
+ },
+ Relation: AndRelation,
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: &Term{
+ Foundry: "new_foundry",
+ Key: "A",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ },
+ {
+ name: "Token with wrapped term",
+ node: &Token{
+ Wrap: &Term{
+ Foundry: "old_foundry",
+ Key: "DET",
+ Layer: "old_layer",
+ Match: MatchEqual,
+ },
+ Rewrites: []Rewrite{
+ {Editor: "test"},
+ },
+ },
+ foundry: "new_foundry",
+ layer: "new_layer",
+ expected: &Token{
+ Wrap: &Term{
+ Foundry: "new_foundry",
+ Key: "DET",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ },
+ Rewrites: []Rewrite{
+ {Editor: "test"},
+ },
+ },
+ },
+ {
+ name: "Token with wrapped OR group - becomes nil",
+ node: &Token{
+ Wrap: &TermGroup{
+ Operands: []Node{
+ &Term{Key: "A", Match: MatchEqual},
+ &Term{Key: "B", Match: MatchEqual},
+ },
+ Relation: OrRelation,
+ },
+ },
+ foundry: "",
+ layer: "",
+ expected: nil,
+ },
+ {
+ name: "Nil node",
+ node: nil,
+ foundry: "foundry",
+ layer: "layer",
+ expected: nil,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := RestrictToObligatory(tt.node, tt.foundry, tt.layer)
+ assert.True(t, NodesEqual(tt.expected, result),
+ "Expected: %+v\nGot: %+v", tt.expected, result)
+ })
+ }
+}
+
+func TestRestrictToObligatoryDoesNotModifyOriginal(t *testing.T) {
+ // Test that the original node is not modified
+ original := &TermGroup{
+ Operands: []Node{
+ &Term{
+ Foundry: "original",
+ Key: "A",
+ Layer: "original",
+ Match: MatchEqual,
+ },
+ &TermGroup{
+ Operands: []Node{
+ &Term{Key: "B", Match: MatchEqual},
+ &Term{Key: "C", Match: MatchEqual},
+ },
+ Relation: OrRelation,
+ },
+ },
+ Relation: AndRelation,
+ }
+
+ // Clone to check that original remains unchanged
+ originalClone := original.Clone()
+
+ // Apply restriction
+ result := RestrictToObligatory(original, "new_foundry", "new_layer")
+
+ // Original should be unchanged
+ assert.True(t, NodesEqual(originalClone, original))
+
+ // Result should be different
+ expected := &Term{
+ Foundry: "new_foundry",
+ Key: "A",
+ Layer: "new_layer",
+ Match: MatchEqual,
+ }
+ assert.True(t, NodesEqual(expected, result))
+}