blob: 464c49778330a68203bd11db37361576ed1cf1b8 [file] [log] [blame]
Akronb7e1f352025-05-16 15:45:23 +02001package parser
2
3import (
4 "encoding/json"
5 "testing"
6
7 "github.com/KorAP/KoralPipe-TermMapper2/pkg/ast"
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10)
11
12func TestParseJSON(t *testing.T) {
13 tests := []struct {
14 name string
15 input string
16 expected ast.Node
17 wantErr bool
18 }{
19 {
20 name: "Parse simple term",
21 input: `{
22 "@type": "koral:term",
23 "foundry": "opennlp",
24 "key": "DET",
25 "layer": "p",
26 "match": "match:eq"
27 }`,
28 expected: &ast.Term{
29 Foundry: "opennlp",
30 Key: "DET",
31 Layer: "p",
32 Match: ast.MatchEqual,
33 },
34 wantErr: false,
35 },
36 {
37 name: "Parse term group with AND relation",
38 input: `{
39 "@type": "koral:termGroup",
40 "operands": [
41 {
42 "@type": "koral:term",
43 "foundry": "opennlp",
44 "key": "DET",
45 "layer": "p",
46 "match": "match:eq"
47 },
48 {
49 "@type": "koral:term",
50 "foundry": "opennlp",
51 "key": "AdjType",
52 "layer": "m",
53 "match": "match:eq",
54 "value": "Pdt"
55 }
56 ],
57 "relation": "relation:and"
58 }`,
59 expected: &ast.TermGroup{
60 Operands: []ast.Node{
61 &ast.Term{
62 Foundry: "opennlp",
63 Key: "DET",
64 Layer: "p",
65 Match: ast.MatchEqual,
66 },
67 &ast.Term{
68 Foundry: "opennlp",
69 Key: "AdjType",
70 Layer: "m",
71 Match: ast.MatchEqual,
72 Value: "Pdt",
73 },
74 },
75 Relation: ast.AndRelation,
76 },
77 wantErr: false,
78 },
79 {
80 name: "Parse token with wrapped term",
81 input: `{
82 "@type": "koral:token",
83 "wrap": {
84 "@type": "koral:term",
85 "foundry": "opennlp",
86 "key": "DET",
87 "layer": "p",
88 "match": "match:eq"
89 }
90 }`,
91 expected: &ast.Token{
92 Wrap: &ast.Term{
93 Foundry: "opennlp",
94 Key: "DET",
95 Layer: "p",
96 Match: ast.MatchEqual,
97 },
98 },
99 wantErr: false,
100 },
101 {
102 name: "Parse complex nested structure",
103 input: `{
104 "@type": "koral:token",
105 "wrap": {
106 "@type": "koral:termGroup",
107 "operands": [
108 {
109 "@type": "koral:term",
110 "foundry": "opennlp",
111 "key": "DET",
112 "layer": "p",
113 "match": "match:eq"
114 },
115 {
116 "@type": "koral:termGroup",
117 "operands": [
118 {
119 "@type": "koral:term",
120 "foundry": "opennlp",
121 "key": "AdjType",
122 "layer": "m",
123 "match": "match:eq",
124 "value": "Pdt"
125 },
126 {
127 "@type": "koral:term",
128 "foundry": "opennlp",
129 "key": "PronType",
130 "layer": "m",
131 "match": "match:ne",
132 "value": "Neg"
133 }
134 ],
135 "relation": "relation:or"
136 }
137 ],
138 "relation": "relation:and"
139 }
140 }`,
141 expected: &ast.Token{
142 Wrap: &ast.TermGroup{
143 Operands: []ast.Node{
144 &ast.Term{
145 Foundry: "opennlp",
146 Key: "DET",
147 Layer: "p",
148 Match: ast.MatchEqual,
149 },
150 &ast.TermGroup{
151 Operands: []ast.Node{
152 &ast.Term{
153 Foundry: "opennlp",
154 Key: "AdjType",
155 Layer: "m",
156 Match: ast.MatchEqual,
157 Value: "Pdt",
158 },
159 &ast.Term{
160 Foundry: "opennlp",
161 Key: "PronType",
162 Layer: "m",
163 Match: ast.MatchNotEqual,
164 Value: "Neg",
165 },
166 },
167 Relation: ast.OrRelation,
168 },
169 },
170 Relation: ast.AndRelation,
171 },
172 },
173 wantErr: false,
174 },
175 {
176 name: "Invalid JSON",
177 input: `{"invalid": json`,
178 wantErr: true,
179 },
180 {
181 name: "Empty JSON",
182 input: `{}`,
183 wantErr: true,
184 },
185 {
186 name: "Invalid node type",
187 input: `{
188 "@type": "koral:unknown",
189 "key": "value"
190 }`,
191 wantErr: true,
192 },
193 }
194
195 for _, tt := range tests {
196 t.Run(tt.name, func(t *testing.T) {
197 result, err := ParseJSON([]byte(tt.input))
198 if tt.wantErr {
199 assert.Error(t, err)
200 return
201 }
202
203 require.NoError(t, err)
204 assert.Equal(t, tt.expected, result)
205 })
206 }
207}
208
209func TestSerializeToJSON(t *testing.T) {
210 tests := []struct {
211 name string
212 input ast.Node
213 expected string
214 wantErr bool
215 }{
216 {
217 name: "Serialize simple term",
218 input: &ast.Term{
219 Foundry: "opennlp",
220 Key: "DET",
221 Layer: "p",
222 Match: ast.MatchEqual,
223 },
224 expected: `{
225 "@type": "koral:term",
226 "foundry": "opennlp",
227 "key": "DET",
228 "layer": "p",
229 "match": "match:eq"
230}`,
231 wantErr: false,
232 },
233 {
234 name: "Serialize term group",
235 input: &ast.TermGroup{
236 Operands: []ast.Node{
237 &ast.Term{
238 Foundry: "opennlp",
239 Key: "DET",
240 Layer: "p",
241 Match: ast.MatchEqual,
242 },
243 &ast.Term{
244 Foundry: "opennlp",
245 Key: "AdjType",
246 Layer: "m",
247 Match: ast.MatchEqual,
248 Value: "Pdt",
249 },
250 },
251 Relation: ast.AndRelation,
252 },
253 expected: `{
254 "@type": "koral:termGroup",
255 "operands": [
256 {
257 "@type": "koral:term",
258 "foundry": "opennlp",
259 "key": "DET",
260 "layer": "p",
261 "match": "match:eq"
262 },
263 {
264 "@type": "koral:term",
265 "foundry": "opennlp",
266 "key": "AdjType",
267 "layer": "m",
268 "match": "match:eq",
269 "value": "Pdt"
270 }
271 ],
272 "relation": "relation:and"
273}`,
274 wantErr: false,
275 },
276 }
277
278 for _, tt := range tests {
279 t.Run(tt.name, func(t *testing.T) {
280 result, err := SerializeToJSON(tt.input)
281 if tt.wantErr {
282 assert.Error(t, err)
283 return
284 }
285
286 require.NoError(t, err)
287 // Compare JSON objects instead of raw strings to avoid whitespace issues
288 var expected, actual interface{}
289 err = json.Unmarshal([]byte(tt.expected), &expected)
290 require.NoError(t, err)
291 err = json.Unmarshal(result, &actual)
292 require.NoError(t, err)
293 assert.Equal(t, expected, actual)
294 })
295 }
296}
297
298func TestRoundTrip(t *testing.T) {
299 // Test that parsing and then serializing produces equivalent JSON
300 input := `{
301 "@type": "koral:token",
302 "wrap": {
303 "@type": "koral:termGroup",
304 "operands": [
305 {
306 "@type": "koral:term",
307 "foundry": "opennlp",
308 "key": "DET",
309 "layer": "p",
310 "match": "match:eq"
311 },
312 {
313 "@type": "koral:term",
314 "foundry": "opennlp",
315 "key": "AdjType",
316 "layer": "m",
317 "match": "match:eq",
318 "value": "Pdt"
319 }
320 ],
321 "relation": "relation:and"
322 }
323 }`
324
325 // Parse JSON to AST
326 node, err := ParseJSON([]byte(input))
327 require.NoError(t, err)
328
329 // Serialize AST back to JSON
330 output, err := SerializeToJSON(node)
331 require.NoError(t, err)
332
333 // Compare JSON objects
334 var expected, actual interface{}
335 err = json.Unmarshal([]byte(input), &expected)
336 require.NoError(t, err)
337 err = json.Unmarshal(output, &actual)
338 require.NoError(t, err)
339 assert.Equal(t, expected, actual)
340}