blob: 189ff68ad3d9f25a9001f017d5686a91cdf7626e [file] [log] [blame]
Akron22322ec2025-05-21 11:17:30 +02001package parser
2
3import (
4 "testing"
5
Akronfa55bb22025-05-26 15:10:42 +02006 "github.com/KorAP/KoralPipe-TermMapper/ast"
Akron22322ec2025-05-21 11:17:30 +02007 "github.com/stretchr/testify/assert"
8 "github.com/stretchr/testify/require"
9)
10
11func TestGrammarParserSimpleTerm(t *testing.T) {
12 tests := []struct {
13 name string
14 input string
15 defaultFoundry string
16 defaultLayer string
17 expected *SimpleTerm
18 expectError bool
19 }{
20 {
21 name: "Foundry layer key value",
22 input: "[opennlp/p=PIDAT:new]",
23 defaultFoundry: "opennlp",
24 defaultLayer: "p",
25 expected: &SimpleTerm{
26 WithFoundryLayer: &FoundryLayerTerm{
27 Foundry: "opennlp",
28 Layer: "p",
29 Key: "PIDAT",
30 Value: "new",
31 },
32 },
33 },
34 {
35 name: "Foundry layer key",
36 input: "[opennlp/p=PIDAT]",
37 defaultFoundry: "opennlp",
38 defaultLayer: "p",
39 expected: &SimpleTerm{
40 WithFoundryLayer: &FoundryLayerTerm{
41 Foundry: "opennlp",
42 Layer: "p",
43 Key: "PIDAT",
44 },
45 },
46 },
47 {
48 name: "Layer key",
49 input: "[p=PIDAT]",
50 defaultFoundry: "opennlp",
51 defaultLayer: "p",
52 expected: &SimpleTerm{
53 WithLayer: &LayerTerm{
54 Layer: "p",
55 Key: "PIDAT",
56 },
57 },
58 },
59 {
60 name: "Simple key",
61 input: "[PIDAT]",
62 defaultFoundry: "opennlp",
63 defaultLayer: "p",
64 expected: &SimpleTerm{
65 SimpleKey: &KeyTerm{
66 Key: "PIDAT",
67 },
68 },
69 },
Akron121c66e2025-06-02 16:34:05 +020070 {
71 name: "Special symbol",
72 input: "[$\\(]",
73 defaultFoundry: "opennlp",
74 defaultLayer: "p",
75 expected: &SimpleTerm{
76 SimpleKey: &KeyTerm{
77 Key: "$(",
78 },
79 },
80 },
81 {
82 name: "Multiple escaped characters",
83 input: "[\\&\\|\\=]",
84 defaultFoundry: "opennlp",
85 defaultLayer: "p",
86 expected: &SimpleTerm{
87 SimpleKey: &KeyTerm{
88 Key: "&|=",
89 },
90 },
91 },
Akron22322ec2025-05-21 11:17:30 +020092 }
93
94 for _, tt := range tests {
95 t.Run(tt.name, func(t *testing.T) {
96 parser, err := NewGrammarParser(tt.defaultFoundry, tt.defaultLayer)
97 require.NoError(t, err)
98
Akronbb5065f2025-05-21 12:44:05 +020099 grammar, err := parser.tokenParser.ParseString("", tt.input)
Akron22322ec2025-05-21 11:17:30 +0200100 if tt.expectError {
101 assert.Error(t, err)
102 return
103 }
104 require.NoError(t, err)
Akronbb5065f2025-05-21 12:44:05 +0200105 require.NotNil(t, grammar.Token, "Expected token expression")
Akron121c66e2025-06-02 16:34:05 +0200106
107 // For testing purposes, unescape the key in the simple term
108 if grammar.Token.Expr.First.Simple.SimpleKey != nil {
109 grammar.Token.Expr.First.Simple.SimpleKey.Key = unescapeString(grammar.Token.Expr.First.Simple.SimpleKey.Key)
110 }
111
Akron22322ec2025-05-21 11:17:30 +0200112 assert.Equal(t, tt.expected, grammar.Token.Expr.First.Simple)
113 })
114 }
115}
116
117func TestGrammarParser(t *testing.T) {
118 tests := []struct {
119 name string
120 input string
121 defaultFoundry string
122 defaultLayer string
123 expected ast.Node
124 expectError bool
125 }{
126 {
127 name: "Simple term with foundry and layer",
128 input: "[opennlp/p=PIDAT]",
129 defaultFoundry: "opennlp",
130 defaultLayer: "p",
131 expected: &ast.Token{
132 Wrap: &ast.Term{
133 Foundry: "opennlp",
134 Key: "PIDAT",
135 Layer: "p",
136 Match: ast.MatchEqual,
137 },
138 },
139 },
140 {
141 name: "Term group with and relation",
142 input: "[opennlp/p=PIDAT & opennlp/p=AdjType:Pdt]",
143 defaultFoundry: "opennlp",
144 defaultLayer: "p",
145 expected: &ast.Token{
146 Wrap: &ast.TermGroup{
147 Operands: []ast.Node{
148 &ast.Term{
149 Foundry: "opennlp",
150 Key: "PIDAT",
151 Layer: "p",
152 Match: ast.MatchEqual,
153 },
154 &ast.Term{
155 Foundry: "opennlp",
156 Key: "AdjType",
157 Layer: "p",
158 Match: ast.MatchEqual,
159 Value: "Pdt",
160 },
161 },
162 Relation: ast.AndRelation,
163 },
164 },
165 },
166 {
167 name: "Term group with or relation",
168 input: "[opennlp/p=PronType:Ind | opennlp/p=PronType:Neg]",
169 defaultFoundry: "opennlp",
170 defaultLayer: "p",
171 expected: &ast.Token{
172 Wrap: &ast.TermGroup{
173 Operands: []ast.Node{
174 &ast.Term{
175 Foundry: "opennlp",
176 Key: "PronType",
177 Layer: "p",
178 Match: ast.MatchEqual,
179 Value: "Ind",
180 },
181 &ast.Term{
182 Foundry: "opennlp",
183 Key: "PronType",
184 Layer: "p",
185 Match: ast.MatchEqual,
186 Value: "Neg",
187 },
188 },
189 Relation: ast.OrRelation,
190 },
191 },
192 },
193 {
194 name: "Complex term group",
195 input: "[opennlp/p=PIDAT & (opennlp/p=PronType:Ind | opennlp/p=PronType:Neg)]",
196 defaultFoundry: "opennlp",
197 defaultLayer: "p",
198 expected: &ast.Token{
199 Wrap: &ast.TermGroup{
200 Operands: []ast.Node{
201 &ast.Term{
202 Foundry: "opennlp",
203 Key: "PIDAT",
204 Layer: "p",
205 Match: ast.MatchEqual,
206 },
207 &ast.TermGroup{
208 Operands: []ast.Node{
209 &ast.Term{
210 Foundry: "opennlp",
211 Key: "PronType",
212 Layer: "p",
213 Match: ast.MatchEqual,
214 Value: "Ind",
215 },
216 &ast.Term{
217 Foundry: "opennlp",
218 Key: "PronType",
219 Layer: "p",
220 Match: ast.MatchEqual,
221 Value: "Neg",
222 },
223 },
224 Relation: ast.OrRelation,
225 },
226 },
227 Relation: ast.AndRelation,
228 },
229 },
230 },
231 }
232
233 for _, tt := range tests {
234 t.Run(tt.name, func(t *testing.T) {
235 parser, err := NewGrammarParser(tt.defaultFoundry, tt.defaultLayer)
236 require.NoError(t, err)
237
238 result, err := parser.Parse(tt.input)
239 if tt.expectError {
240 assert.Error(t, err)
241 return
242 }
243 require.NoError(t, err)
244 assert.Equal(t, tt.expected, result)
245 })
246 }
247}
Akronbb5065f2025-05-21 12:44:05 +0200248
249func TestMappingRules(t *testing.T) {
250 tests := []struct {
251 name string
252 input string
253 expected *MappingResult
254 wantErr bool
255 }{
256 {
257 name: "Simple PIDAT mapping",
258 input: "[PIDAT] <> [opennlp/p=PIDAT & opennlp/p=AdjType:Pdt]",
259 expected: &MappingResult{
260 Upper: &ast.Token{
261 Wrap: &ast.Term{
262 Key: "PIDAT",
263 Match: ast.MatchEqual,
264 },
265 },
266 Lower: &ast.Token{
267 Wrap: &ast.TermGroup{
268 Relation: ast.AndRelation,
269 Operands: []ast.Node{
270 &ast.Term{
271 Foundry: "opennlp",
272 Layer: "p",
273 Key: "PIDAT",
274 Match: ast.MatchEqual,
275 },
276 &ast.Term{
277 Foundry: "opennlp",
278 Layer: "p",
279 Key: "AdjType",
280 Value: "Pdt",
281 Match: ast.MatchEqual,
282 },
283 },
284 },
285 },
286 },
287 },
288 {
289 name: "PAV mapping",
290 input: "[PAV] <> [ADV & PronType:Dem]",
291 expected: &MappingResult{
292 Upper: &ast.Token{
293 Wrap: &ast.Term{
294 Key: "PAV",
295 Match: ast.MatchEqual,
296 },
297 },
298 Lower: &ast.Token{
299 Wrap: &ast.TermGroup{
300 Relation: ast.AndRelation,
301 Operands: []ast.Node{
302 &ast.Term{
303 Key: "ADV",
304 Match: ast.MatchEqual,
305 },
306 &ast.Term{
307 Key: "PronType",
308 Value: "Dem",
309 Match: ast.MatchEqual,
310 },
311 },
312 },
313 },
314 },
315 },
316 {
Akron76b87972025-06-02 16:59:59 +0200317 name: "PAV mapping with special character",
318 input: "[$\\(] <> [ADV & PronType:Dem]",
319 expected: &MappingResult{
320 Upper: &ast.Token{
321 Wrap: &ast.Term{
322 Key: "$(",
323 Match: ast.MatchEqual,
324 },
325 },
326 Lower: &ast.Token{
327 Wrap: &ast.TermGroup{
328 Relation: ast.AndRelation,
329 Operands: []ast.Node{
330 &ast.Term{
331 Key: "ADV",
332 Match: ast.MatchEqual,
333 },
334 &ast.Term{
335 Key: "PronType",
336 Value: "Dem",
337 Match: ast.MatchEqual,
338 },
339 },
340 },
341 },
342 },
343 },
344 {
Akronbb5065f2025-05-21 12:44:05 +0200345 name: "Invalid mapping syntax",
346 input: "[PAV] -> [ADV]",
347 wantErr: true,
348 },
349 {
350 name: "Missing closing bracket",
351 input: "[PAV <> [ADV]",
352 wantErr: true,
353 },
354 }
355
356 parser, err := NewGrammarParser("", "")
357 assert.NoError(t, err)
358
359 for _, tt := range tests {
360 t.Run(tt.name, func(t *testing.T) {
361 result, err := parser.ParseMapping(tt.input)
362 if tt.wantErr {
363 assert.Error(t, err)
364 return
365 }
366 assert.NoError(t, err)
367 assert.Equal(t, tt.expected, result)
368 })
369 }
370}