blob: 07bd176818eddfc1734cb46beb5c203bcb6987bf [file] [log] [blame]
Akron49ceeb42025-05-23 17:46:01 +02001package main
2
3import (
4 "bytes"
5 "encoding/json"
6 "io"
7 "net/http"
8 "net/http/httptest"
Akron49ceeb42025-05-23 17:46:01 +02009 "testing"
10
Akrona00d4752025-05-26 17:34:36 +020011 tmconfig "github.com/KorAP/KoralPipe-TermMapper/config"
Akronfa55bb22025-05-26 15:10:42 +020012 "github.com/KorAP/KoralPipe-TermMapper/mapper"
Akron49ceeb42025-05-23 17:46:01 +020013 "github.com/gofiber/fiber/v2"
14 "github.com/stretchr/testify/assert"
15 "github.com/stretchr/testify/require"
16)
17
18func TestTransformEndpoint(t *testing.T) {
Akrona00d4752025-05-26 17:34:36 +020019 // Create test mapping list
20 mappingList := tmconfig.MappingList{
21 ID: "test-mapper",
22 FoundryA: "opennlp",
23 LayerA: "p",
24 FoundryB: "upos",
25 LayerB: "p",
26 Mappings: []tmconfig.MappingRule{
27 "[PIDAT] <> [opennlp/p=PIDAT & opennlp/p=AdjType:Pdt]",
28 "[DET] <> [opennlp/p=DET]",
29 },
30 }
Akron49ceeb42025-05-23 17:46:01 +020031
32 // Create mapper
Akrona00d4752025-05-26 17:34:36 +020033 m, err := mapper.NewMapper([]tmconfig.MappingList{mappingList})
Akron49ceeb42025-05-23 17:46:01 +020034 require.NoError(t, err)
35
36 // Create fiber app
37 app := fiber.New()
38 setupRoutes(app, m)
39
40 tests := []struct {
41 name string
42 mapID string
43 direction string
44 foundryA string
45 foundryB string
46 layerA string
47 layerB string
48 input string
49 expectedCode int
50 expectedBody string
51 expectedError string
52 }{
53 {
54 name: "Simple A to B mapping",
55 mapID: "test-mapper",
56 direction: "atob",
57 input: `{
58 "@type": "koral:token",
59 "wrap": {
60 "@type": "koral:term",
61 "foundry": "opennlp",
62 "key": "PIDAT",
63 "layer": "p",
64 "match": "match:eq"
65 }
66 }`,
67 expectedCode: http.StatusOK,
68 expectedBody: `{
69 "@type": "koral:token",
70 "wrap": {
71 "@type": "koral:termGroup",
72 "operands": [
73 {
74 "@type": "koral:term",
75 "foundry": "opennlp",
76 "key": "PIDAT",
77 "layer": "p",
78 "match": "match:eq"
79 },
80 {
81 "@type": "koral:term",
82 "foundry": "opennlp",
83 "key": "AdjType",
84 "layer": "p",
85 "match": "match:eq",
86 "value": "Pdt"
87 }
88 ],
89 "relation": "relation:and"
90 }
91 }`,
92 },
93 {
94 name: "B to A mapping",
95 mapID: "test-mapper",
96 direction: "btoa",
97 input: `{
98 "@type": "koral:token",
99 "wrap": {
100 "@type": "koral:termGroup",
101 "operands": [
102 {
103 "@type": "koral:term",
104 "foundry": "opennlp",
105 "key": "PIDAT",
106 "layer": "p",
107 "match": "match:eq"
108 },
109 {
110 "@type": "koral:term",
111 "foundry": "opennlp",
112 "key": "AdjType",
113 "layer": "p",
114 "match": "match:eq",
115 "value": "Pdt"
116 }
117 ],
118 "relation": "relation:and"
119 }
120 }`,
121 expectedCode: http.StatusOK,
122 expectedBody: `{
123 "@type": "koral:token",
124 "wrap": {
125 "@type": "koral:term",
126 "foundry": "opennlp",
127 "key": "PIDAT",
128 "layer": "p",
129 "match": "match:eq"
130 }
131 }`,
132 },
133 {
134 name: "Mapping with foundry override",
135 mapID: "test-mapper",
136 direction: "atob",
137 foundryB: "custom",
138 input: `{
139 "@type": "koral:token",
140 "wrap": {
141 "@type": "koral:term",
142 "foundry": "opennlp",
143 "key": "PIDAT",
144 "layer": "p",
145 "match": "match:eq"
146 }
147 }`,
148 expectedCode: http.StatusOK,
149 expectedBody: `{
150 "@type": "koral:token",
151 "wrap": {
152 "@type": "koral:termGroup",
153 "operands": [
154 {
155 "@type": "koral:term",
156 "foundry": "custom",
157 "key": "PIDAT",
158 "layer": "p",
159 "match": "match:eq"
160 },
161 {
162 "@type": "koral:term",
163 "foundry": "custom",
164 "key": "AdjType",
165 "layer": "p",
166 "match": "match:eq",
167 "value": "Pdt"
168 }
169 ],
170 "relation": "relation:and"
171 }
172 }`,
173 },
174 {
175 name: "Invalid mapping ID",
176 mapID: "nonexistent",
177 direction: "atob",
178 input: `{"@type": "koral:token"}`,
179 expectedCode: http.StatusInternalServerError,
180 expectedError: "mapping list with ID nonexistent not found",
181 },
182 {
183 name: "Invalid direction",
184 mapID: "test-mapper",
185 direction: "invalid",
186 input: `{"@type": "koral:token"}`,
187 expectedCode: http.StatusBadRequest,
188 expectedError: "invalid direction, must be 'atob' or 'btoa'",
189 },
190 {
191 name: "Invalid JSON",
192 mapID: "test-mapper",
193 direction: "atob",
194 input: `invalid json`,
195 expectedCode: http.StatusBadRequest,
196 expectedError: "invalid JSON in request body",
197 },
198 }
199
200 for _, tt := range tests {
201 t.Run(tt.name, func(t *testing.T) {
202 // Build URL with query parameters
203 url := "/" + tt.mapID + "/query"
204 if tt.direction != "" {
205 url += "?dir=" + tt.direction
206 }
207 if tt.foundryA != "" {
208 url += "&foundryA=" + tt.foundryA
209 }
210 if tt.foundryB != "" {
211 url += "&foundryB=" + tt.foundryB
212 }
213 if tt.layerA != "" {
214 url += "&layerA=" + tt.layerA
215 }
216 if tt.layerB != "" {
217 url += "&layerB=" + tt.layerB
218 }
219
220 // Make request
221 req := httptest.NewRequest(http.MethodPost, url, bytes.NewBufferString(tt.input))
222 req.Header.Set("Content-Type", "application/json")
223 resp, err := app.Test(req)
224 require.NoError(t, err)
225 defer resp.Body.Close()
226
227 // Check status code
228 assert.Equal(t, tt.expectedCode, resp.StatusCode)
229
230 // Read response body
231 body, err := io.ReadAll(resp.Body)
232 require.NoError(t, err)
233
234 if tt.expectedError != "" {
235 // Check error message
236 var errResp fiber.Map
237 err = json.Unmarshal(body, &errResp)
238 require.NoError(t, err)
239 assert.Equal(t, tt.expectedError, errResp["error"])
240 } else {
241 // Compare JSON responses
Akron121c66e2025-06-02 16:34:05 +0200242 var expected, actual any
Akron49ceeb42025-05-23 17:46:01 +0200243 err = json.Unmarshal([]byte(tt.expectedBody), &expected)
244 require.NoError(t, err)
245 err = json.Unmarshal(body, &actual)
246 require.NoError(t, err)
247 assert.Equal(t, expected, actual)
248 }
249 })
250 }
251}
252
253func TestHealthEndpoint(t *testing.T) {
Akrona00d4752025-05-26 17:34:36 +0200254 // Create test mapping list
255 mappingList := tmconfig.MappingList{
256 ID: "test-mapper",
257 Mappings: []tmconfig.MappingRule{
258 "[A] <> [B]",
259 },
260 }
Akron49ceeb42025-05-23 17:46:01 +0200261
Akrona00d4752025-05-26 17:34:36 +0200262 // Create mapper
263 m, err := mapper.NewMapper([]tmconfig.MappingList{mappingList})
Akron49ceeb42025-05-23 17:46:01 +0200264 require.NoError(t, err)
265
266 // Create fiber app
267 app := fiber.New()
268 setupRoutes(app, m)
269
270 // Test health endpoint
271 req := httptest.NewRequest(http.MethodGet, "/health", nil)
272 resp, err := app.Test(req)
273 require.NoError(t, err)
274 defer resp.Body.Close()
275
276 assert.Equal(t, http.StatusOK, resp.StatusCode)
277 body, err := io.ReadAll(resp.Body)
278 require.NoError(t, err)
279 assert.Equal(t, "OK", string(body))
280}