blob: 0daaf7c3a6762431c027bcabf4b488a38314b9d5 [file] [log] [blame]
Akronb7e1f352025-05-16 15:45:23 +02001package ast
2
3import (
Akron8b3942b2025-05-23 13:36:37 +02004 "encoding/json"
Akronb7e1f352025-05-16 15:45:23 +02005 "testing"
6
7 "github.com/stretchr/testify/assert"
8)
9
10func TestNodeTypes(t *testing.T) {
11 tests := []struct {
12 name string
13 node Node
14 expected NodeType
15 }{
16 {
17 name: "Token node returns correct type",
18 node: &Token{Wrap: &Term{}},
19 expected: TokenNode,
20 },
21 {
22 name: "TermGroup node returns correct type",
23 node: &TermGroup{
24 Operands: []Node{&Term{}},
25 Relation: AndRelation,
26 },
27 expected: TermGroupNode,
28 },
29 {
30 name: "Term node returns correct type",
31 node: &Term{
32 Foundry: "opennlp",
33 Key: "DET",
34 Layer: "p",
35 Match: MatchEqual,
36 },
37 expected: TermNode,
38 },
Akron1a5fccd2025-05-27 09:54:09 +020039 {
40 name: "Rewrite node returns correct type",
41 node: &Rewrite{
42 Editor: "Kustvakt",
43 Operation: "operation:injection",
44 Scope: "foundry",
45 Src: "Kustvakt",
46 },
47 expected: RewriteNode,
48 },
Akronb7e1f352025-05-16 15:45:23 +020049 }
50
51 for _, tt := range tests {
52 t.Run(tt.name, func(t *testing.T) {
53 assert.Equal(t, tt.expected, tt.node.Type())
54 })
55 }
56}
57
58func TestTermGroupConstruction(t *testing.T) {
59 term1 := &Term{
60 Foundry: "opennlp",
61 Key: "DET",
62 Layer: "p",
63 Match: MatchEqual,
64 }
65
66 term2 := &Term{
67 Foundry: "opennlp",
68 Key: "AdjType",
69 Layer: "m",
70 Match: MatchEqual,
71 Value: "Pdt",
72 }
73
Akron1a5fccd2025-05-27 09:54:09 +020074 rewrites := []Rewrite{
75 {
76 Editor: "Kustvakt",
77 Operation: "operation:injection",
78 Scope: "foundry",
79 Src: "Kustvakt",
80 Comment: "Default foundry has been added.",
81 },
82 }
83
Akronb7e1f352025-05-16 15:45:23 +020084 group := &TermGroup{
85 Operands: []Node{term1, term2},
86 Relation: AndRelation,
Akron1a5fccd2025-05-27 09:54:09 +020087 Rewrites: rewrites,
Akronb7e1f352025-05-16 15:45:23 +020088 }
89
90 assert.Len(t, group.Operands, 2)
91 assert.Equal(t, AndRelation, group.Relation)
92 assert.Equal(t, TermGroupNode, group.Type())
Akron1a5fccd2025-05-27 09:54:09 +020093 assert.Equal(t, rewrites, group.Rewrites)
Akronb7e1f352025-05-16 15:45:23 +020094
95 // Test operands are correctly set
96 assert.Equal(t, term1, group.Operands[0])
97 assert.Equal(t, term2, group.Operands[1])
98}
99
100func TestTokenConstruction(t *testing.T) {
101 term := &Term{
102 Foundry: "opennlp",
103 Key: "DET",
104 Layer: "p",
105 Match: MatchEqual,
106 }
107
Akron1a5fccd2025-05-27 09:54:09 +0200108 rewrites := []Rewrite{
109 {
110 Editor: "Kustvakt",
111 Operation: "operation:injection",
112 Scope: "foundry",
113 Src: "Kustvakt",
114 Comment: "Default foundry has been added.",
115 },
116 }
117
118 token := &Token{
119 Wrap: term,
120 Rewrites: rewrites,
121 }
Akronb7e1f352025-05-16 15:45:23 +0200122
123 assert.Equal(t, TokenNode, token.Type())
124 assert.Equal(t, term, token.Wrap)
Akron1a5fccd2025-05-27 09:54:09 +0200125 assert.Equal(t, rewrites, token.Rewrites)
Akronb7e1f352025-05-16 15:45:23 +0200126}
127
128func TestTermConstruction(t *testing.T) {
129 tests := []struct {
130 name string
131 term *Term
132 foundry string
133 key string
134 layer string
135 match MatchType
136 hasValue bool
137 value string
Akron1a5fccd2025-05-27 09:54:09 +0200138 rewrites []Rewrite
Akronb7e1f352025-05-16 15:45:23 +0200139 }{
140 {
141 name: "Term without value",
142 term: &Term{
143 Foundry: "opennlp",
144 Key: "DET",
145 Layer: "p",
146 Match: MatchEqual,
147 },
148 foundry: "opennlp",
149 key: "DET",
150 layer: "p",
151 match: MatchEqual,
152 hasValue: false,
153 },
154 {
155 name: "Term with value",
156 term: &Term{
157 Foundry: "opennlp",
158 Key: "AdjType",
159 Layer: "m",
160 Match: MatchEqual,
161 Value: "Pdt",
162 },
163 foundry: "opennlp",
164 key: "AdjType",
165 layer: "m",
166 match: MatchEqual,
167 hasValue: true,
168 value: "Pdt",
169 },
170 {
171 name: "Term with not equal match",
172 term: &Term{
173 Foundry: "opennlp",
174 Key: "DET",
175 Layer: "p",
176 Match: MatchNotEqual,
177 },
178 foundry: "opennlp",
179 key: "DET",
180 layer: "p",
181 match: MatchNotEqual,
182 hasValue: false,
183 },
Akron1a5fccd2025-05-27 09:54:09 +0200184 {
185 name: "Term with rewrites",
186 term: &Term{
187 Foundry: "opennlp",
188 Key: "DET",
189 Layer: "p",
190 Match: MatchEqual,
191 Rewrites: []Rewrite{
192 {
193 Editor: "Kustvakt",
194 Operation: "operation:injection",
195 Scope: "foundry",
196 Src: "Kustvakt",
197 Comment: "Default foundry has been added.",
198 },
199 },
200 },
201 foundry: "opennlp",
202 key: "DET",
203 layer: "p",
204 match: MatchEqual,
205 hasValue: false,
206 rewrites: []Rewrite{
207 {
208 Editor: "Kustvakt",
209 Operation: "operation:injection",
210 Scope: "foundry",
211 Src: "Kustvakt",
212 Comment: "Default foundry has been added.",
213 },
214 },
215 },
Akronb7e1f352025-05-16 15:45:23 +0200216 }
217
218 for _, tt := range tests {
219 t.Run(tt.name, func(t *testing.T) {
220 assert.Equal(t, TermNode, tt.term.Type())
221 assert.Equal(t, tt.foundry, tt.term.Foundry)
222 assert.Equal(t, tt.key, tt.term.Key)
223 assert.Equal(t, tt.layer, tt.term.Layer)
224 assert.Equal(t, tt.match, tt.term.Match)
225 if tt.hasValue {
226 assert.Equal(t, tt.value, tt.term.Value)
227 } else {
228 assert.Empty(t, tt.term.Value)
229 }
Akron1a5fccd2025-05-27 09:54:09 +0200230 if tt.rewrites != nil {
231 assert.Equal(t, tt.rewrites, tt.term.Rewrites)
232 } else {
233 assert.Empty(t, tt.term.Rewrites)
234 }
Akronb7e1f352025-05-16 15:45:23 +0200235 })
236 }
237}
238
239func TestPatternAndReplacement(t *testing.T) {
240 // Create a simple pattern
241 patternTerm := &Term{
242 Foundry: "opennlp",
243 Key: "DET",
244 Layer: "p",
245 Match: MatchEqual,
246 }
247 pattern := Pattern{Root: patternTerm}
248
249 // Create a simple replacement
250 replacementTerm := &Term{
251 Foundry: "opennlp",
252 Key: "COMBINED_DET",
253 Layer: "p",
254 Match: MatchEqual,
255 }
256 replacement := Replacement{Root: replacementTerm}
257
258 // Test pattern
259 assert.NotNil(t, pattern.Root)
260 assert.Equal(t, patternTerm, pattern.Root)
261
262 // Test replacement
263 assert.NotNil(t, replacement.Root)
264 assert.Equal(t, replacementTerm, replacement.Root)
265}
Akron8b3942b2025-05-23 13:36:37 +0200266
267func TestCatchallNode(t *testing.T) {
268 tests := []struct {
269 name string
270 nodeType string
271 content string
272 wrap Node
273 operands []Node
274 expectType NodeType
275 }{
276 {
277 name: "CatchallNode with custom type",
278 nodeType: "customType",
279 content: `{"key": "value"}`,
280 expectType: NodeType("customType"),
281 },
282 {
283 name: "CatchallNode with wrapped term",
284 nodeType: "wrapper",
285 content: `{"key": "value"}`,
286 wrap: &Term{
287 Foundry: "test",
288 Key: "TEST",
289 Layer: "x",
290 Match: MatchEqual,
291 },
292 expectType: NodeType("wrapper"),
293 },
294 {
295 name: "CatchallNode with operands",
296 nodeType: "custom_group",
297 content: `{"key": "value"}`,
298 operands: []Node{
299 &Term{Foundry: "test1", Key: "TEST1", Layer: "x", Match: MatchEqual},
300 &Term{Foundry: "test2", Key: "TEST2", Layer: "y", Match: MatchEqual},
301 },
302 expectType: NodeType("custom_group"),
303 },
304 }
305
306 for _, tt := range tests {
307 t.Run(tt.name, func(t *testing.T) {
308 rawContent := json.RawMessage(tt.content)
309 node := &CatchallNode{
310 NodeType: tt.nodeType,
311 RawContent: rawContent,
312 Wrap: tt.wrap,
313 Operands: tt.operands,
314 }
315
316 assert.Equal(t, tt.expectType, node.Type())
317 if tt.wrap != nil {
318 assert.Equal(t, tt.wrap, node.Wrap)
319 }
320 if tt.operands != nil {
321 assert.Equal(t, tt.operands, node.Operands)
322 }
323 assert.Equal(t, rawContent, node.RawContent)
324 })
325 }
326}
327
Akron1a5fccd2025-05-27 09:54:09 +0200328func TestRewriteConstruction(t *testing.T) {
329 rewrite := &Rewrite{
330 Editor: "Kustvakt",
331 Operation: "operation:injection",
332 Scope: "foundry",
333 Src: "Kustvakt",
334 Comment: "Default foundry has been added.",
335 }
336
337 assert.Equal(t, RewriteNode, rewrite.Type())
338 assert.Equal(t, "Kustvakt", rewrite.Editor)
339 assert.Equal(t, "operation:injection", rewrite.Operation)
340 assert.Equal(t, "foundry", rewrite.Scope)
341 assert.Equal(t, "Kustvakt", rewrite.Src)
342 assert.Equal(t, "Default foundry has been added.", rewrite.Comment)
343}
344
Akron8b3942b2025-05-23 13:36:37 +0200345func TestComplexNestedStructures(t *testing.T) {
346 // Create a complex nested structure
347 innerGroup1 := &TermGroup{
348 Operands: []Node{
349 &Term{Foundry: "f1", Key: "k1", Layer: "l1", Match: MatchEqual},
350 &Term{Foundry: "f2", Key: "k2", Layer: "l2", Match: MatchNotEqual},
351 },
352 Relation: AndRelation,
353 }
354
355 innerGroup2 := &TermGroup{
356 Operands: []Node{
357 &Term{Foundry: "f3", Key: "k3", Layer: "l3", Match: MatchEqual},
358 &Term{Foundry: "f4", Key: "k4", Layer: "l4", Match: MatchEqual, Value: "test"},
359 },
360 Relation: OrRelation,
361 }
362
363 topGroup := &TermGroup{
364 Operands: []Node{
365 innerGroup1,
366 innerGroup2,
367 &Token{Wrap: &Term{Foundry: "f5", Key: "k5", Layer: "l5", Match: MatchEqual}},
368 },
369 Relation: AndRelation,
370 }
371
372 assert.Equal(t, TermGroupNode, topGroup.Type())
373 assert.Len(t, topGroup.Operands, 3)
374 assert.Equal(t, AndRelation, topGroup.Relation)
375
376 // Test inner groups
377 group1 := topGroup.Operands[0].(*TermGroup)
378 assert.Len(t, group1.Operands, 2)
379 assert.Equal(t, AndRelation, group1.Relation)
380
381 group2 := topGroup.Operands[1].(*TermGroup)
382 assert.Len(t, group2.Operands, 2)
383 assert.Equal(t, OrRelation, group2.Relation)
384
385 // Test token wrapping
386 token := topGroup.Operands[2].(*Token)
387 assert.NotNil(t, token.Wrap)
388 assert.Equal(t, TermNode, token.Wrap.Type())
389}
390
391func TestEdgeCases(t *testing.T) {
392 tests := []struct {
393 name string
394 test func(t *testing.T)
395 }{
396 {
397 name: "Empty TermGroup",
398 test: func(t *testing.T) {
399 group := &TermGroup{
400 Operands: []Node{},
401 Relation: AndRelation,
402 }
403 assert.Empty(t, group.Operands)
404 assert.Equal(t, AndRelation, group.Relation)
405 },
406 },
407 {
408 name: "Token with nil wrap",
409 test: func(t *testing.T) {
410 token := &Token{Wrap: nil}
411 assert.Equal(t, TokenNode, token.Type())
412 assert.Nil(t, token.Wrap)
413 },
414 },
415 {
416 name: "Term with empty strings",
417 test: func(t *testing.T) {
418 term := &Term{
419 Foundry: "",
420 Key: "",
421 Layer: "",
422 Match: MatchEqual,
423 Value: "",
424 }
425 assert.Equal(t, TermNode, term.Type())
426 assert.Empty(t, term.Foundry)
427 assert.Empty(t, term.Key)
428 assert.Empty(t, term.Layer)
429 assert.Empty(t, term.Value)
430 },
431 },
432 {
433 name: "Complex Pattern and Replacement",
434 test: func(t *testing.T) {
435 // Create a complex pattern
436 patternGroup := &TermGroup{
437 Operands: []Node{
438 &Term{Foundry: "f1", Key: "k1", Layer: "l1", Match: MatchEqual},
439 &Token{Wrap: &Term{Foundry: "f2", Key: "k2", Layer: "l2", Match: MatchNotEqual}},
440 },
441 Relation: OrRelation,
442 }
443 pattern := Pattern{Root: patternGroup}
444
445 // Create a complex replacement
446 replacementGroup := &TermGroup{
447 Operands: []Node{
448 &Term{Foundry: "f3", Key: "k3", Layer: "l3", Match: MatchEqual},
449 &Term{Foundry: "f4", Key: "k4", Layer: "l4", Match: MatchEqual},
450 },
451 Relation: AndRelation,
452 }
453 replacement := Replacement{Root: replacementGroup}
454
455 assert.Equal(t, TermGroupNode, pattern.Root.Type())
456 assert.Equal(t, TermGroupNode, replacement.Root.Type())
457 },
458 },
459 }
460
461 for _, tt := range tests {
462 t.Run(tt.name, tt.test)
463 }
464}