Generate VPE HTTP handler
[govpp.git] / binapigen / generate_test.go
1 //  Copyright (c) 2020 Cisco and/or its affiliates.
2 //
3 //  Licensed under the Apache License, Version 2.0 (the "License");
4 //  you may not use this file except in compliance with the License.
5 //  You may obtain a copy of the License at:
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 //  Unless required by applicable law or agreed to in writing, software
10 //  distributed under the License is distributed on an "AS IS" BASIS,
11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //  See the License for the specific language governing permissions and
13 //  limitations under the License.
14
15 package binapigen
16
17 import (
18         "os"
19         "testing"
20
21         . "github.com/onsi/gomega"
22
23         "git.fd.io/govpp.git/binapi/ip_types"
24         "git.fd.io/govpp.git/binapigen/vppapi"
25 )
26
27 const testOutputDir = "test_output_dir"
28
29 func GenerateFromFile(file string, opts Options) error {
30         apifile, err := vppapi.ParseFile(file)
31         if err != nil {
32                 return err
33         }
34         gen, err := New(opts, []*vppapi.File{apifile}, nil)
35         if err != nil {
36                 return err
37         }
38         for _, file := range gen.Files {
39                 if !file.Generate {
40                         continue
41                 }
42                 GenerateAPI(gen, file)
43         }
44         if err = gen.Generate(); err != nil {
45                 return err
46         }
47         return nil
48 }
49
50 func TestGenerateFromFile(t *testing.T) {
51         RegisterTestingT(t)
52
53         // remove directory created during test
54         defer os.RemoveAll(testOutputDir)
55
56         opts := Options{OutputDir: testOutputDir}
57         err := GenerateFromFile("vppapi/testdata/acl.api.json", opts)
58         Expect(err).ShouldNot(HaveOccurred())
59         fileInfo, err := os.Stat(testOutputDir + "/acl/acl.ba.go")
60         Expect(err).ShouldNot(HaveOccurred())
61         Expect(fileInfo.IsDir()).To(BeFalse())
62         Expect(fileInfo.Name()).To(BeEquivalentTo("acl.ba.go"))
63 }
64
65 func TestGenerateFromFileInputError(t *testing.T) {
66         RegisterTestingT(t)
67
68         opts := Options{OutputDir: testOutputDir}
69         err := GenerateFromFile("vppapi/testdata/nonexisting.json", opts)
70         Expect(err).Should(HaveOccurred())
71         Expect(err.Error()).To(ContainSubstring("unsupported"))
72 }
73
74 func TestGenerateFromFileReadJsonError(t *testing.T) {
75         RegisterTestingT(t)
76
77         opts := Options{OutputDir: testOutputDir}
78         err := GenerateFromFile("vppapi/testdata/input-read-json-error.json", opts)
79         Expect(err).Should(HaveOccurred())
80         Expect(err.Error()).To(ContainSubstring("unsupported"))
81 }
82
83 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
84         RegisterTestingT(t)
85
86         // generate package throws panic, recover after it
87         defer func() {
88                 if recovery := recover(); recovery != nil {
89                         t.Logf("Recovered from panic: %v", recovery)
90                 }
91                 os.RemoveAll(testOutputDir)
92         }()
93
94         opts := Options{OutputDir: testOutputDir}
95         err := GenerateFromFile("vppapi/testdata/input-generate-error.json", opts)
96         Expect(err).Should(HaveOccurred())
97 }
98
99 func TestAddress(t *testing.T) {
100         RegisterTestingT(t)
101
102         addr := ip_types.AddressUnionIP4(ip_types.IP4Address{10, 20, 0, 1})
103         t.Logf("addr: %v (%#v)", addr, addr)
104
105         ip4 := addr.GetIP4()
106         t.Logf("ip4: %v", ip4)
107         addr.SetIP4(ip_types.IP4Address{192, 168, 1, 1})
108         t.Logf("ip4: %v", addr.GetIP4())
109
110         Expect(addr.GetIP4()).To(Equal(ip_types.IP4Address{192, 168, 1, 1}))
111 }
112
113 /*func TestGetContext(t *testing.T) {
114         RegisterTestingT(t)
115         outDir := "test_output_directory"
116         result, err := newContext("testdata/af_packet.api.json", outDir)
117         Expect(err).ShouldNot(HaveOccurred())
118         Expect(result).ToNot(BeNil())
119         Expect(result.outputFile).To(BeEquivalentTo(outDir + "/af_packet/af_packet.ba.go"))
120 }
121
122 func TestGetContextNoJsonFile(t *testing.T) {
123         RegisterTestingT(t)
124         outDir := "test_output_directory"
125         result, err := newContext("testdata/input.txt", outDir)
126         Expect(err).Should(HaveOccurred())
127         Expect(err.Error()).To(ContainSubstring("invalid input file name"))
128         Expect(result).To(BeNil())
129 }
130
131 func TestGetContextInterfaceJson(t *testing.T) {
132         RegisterTestingT(t)
133         outDir := "test_output_directory"
134         result, err := newContext("testdata/ip.api.json", outDir)
135         Expect(err).ShouldNot(HaveOccurred())
136         Expect(result).ToNot(BeNil())
137         Expect(result.outputFile)
138         Expect(result.outputFile).To(BeEquivalentTo(outDir + "/ip/ip.ba.go"))
139 }*/
140
141 /*func TestGeneratePackage(t *testing.T) {
142         RegisterTestingT(t)
143         // prepare context
144         testCtx := new(GenFile)
145         testCtx.packageName = "test-package-name"
146
147         // prepare input/output output files
148         inputData, err := ioutil.ReadFile("testdata/ip.api.json")
149         Expect(err).ShouldNot(HaveOccurred())
150         jsonRoot, err := parseInputJSON(inputData)
151         Expect(err).ShouldNot(HaveOccurred())
152         testCtx.file, err = parseModule(testCtx, jsonRoot)
153         Expect(err).ShouldNot(HaveOccurred())
154         outDir := "test_output_directory"
155         outFile, err := os.Create(outDir)
156         Expect(err).ShouldNot(HaveOccurred())
157         defer os.RemoveAll(outDir)
158
159         // prepare writer
160         writer := bufio.NewWriter(outFile)
161         Expect(writer.Buffered()).To(BeZero())
162         err = GenerateFileBinapi(testCtx, writer)
163         Expect(err).ShouldNot(HaveOccurred())
164 }
165
166 func TestGenerateMessageType(t *testing.T) {
167         RegisterTestingT(t)
168         // prepare context
169         testCtx := new(GenFile)
170         testCtx.packageName = "test-package-name"
171
172         // prepare input/output output files
173         inputData, err := ioutil.ReadFile("testdata/ip.api.json")
174         Expect(err).ShouldNot(HaveOccurred())
175         jsonRoot, err := parseInputJSON(inputData)
176         Expect(err).ShouldNot(HaveOccurred())
177         outDir := "test_output_directory"
178         outFile, err := os.Create(outDir)
179         Expect(err).ShouldNot(HaveOccurred())
180         testCtx.file, err = parseModule(testCtx, jsonRoot)
181         Expect(err).ShouldNot(HaveOccurred())
182         defer os.RemoveAll(outDir)
183
184         // prepare writer
185         writer := bufio.NewWriter(outFile)
186
187         for _, msg := range testCtx.file.Messages {
188                 genMessage(testCtx, writer, &msg)
189                 Expect(writer.Buffered()).ToNot(BeZero())
190         }
191 }*/
192
193 /*func TestGenerateMessageName(t *testing.T) {
194         RegisterTestingT(t)
195         // prepare context
196         testCtx := new(context)
197         testCtx.packageName = "test-package-name"
198
199         // prepare input/output output files
200         inputData, err := readFile("testdata/ip.api.json")
201         Expect(err).ShouldNot(HaveOccurred())
202         testCtx.inputBuff = bytes.NewBuffer(inputData)
203         inFile, _ := parseJSON(inputData)
204         outDir := "test_output_directory"
205         outFile, err := os.Create(outDir)
206         Expect(err).ShouldNot(HaveOccurred())
207         defer os.RemoveAll(outDir)
208
209         // prepare writer
210         writer := bufio.NewWriter(outFile)
211
212         types := inFile.Map("types")
213         Expect(types.Len()).To(BeEquivalentTo(1))
214         for i := 0; i < types.Len(); i++ {
215                 typ := types.At(i)
216                 Expect(writer.Buffered()).To(BeZero())
217                 err := genMessage(testCtx, writer, typ, false)
218                 Expect(err).ShouldNot(HaveOccurred())
219                 Expect(writer.Buffered()).ToNot(BeZero())
220
221         }
222 }
223
224 func TestGenerateMessageFieldTypes(t *testing.T) {
225         // expected results according to acl.api.json in testdata
226         expectedTypes := []string{
227                 "\tIsPermit uint8",
228                 "\tIsIpv6 uint8",
229                 "\tSrcIPAddr []byte     `struc:\"[16]byte\"`",
230                 "\tSrcIPPrefixLen uint8",
231                 "\tDstIPAddr []byte     `struc:\"[16]byte\"`",
232                 "\tDstIPPrefixLen uint8",
233                 "\tProto uint8",
234                 "\tSrcportOrIcmptypeFirst uint16",
235                 "\tSrcportOrIcmptypeLast uint16",
236                 "\tDstportOrIcmpcodeFirst uint16",
237                 "\tDstportOrIcmpcodeLast uint16",
238                 "\tTCPFlagsMask uint8",
239                 "\tTCPFlagsValue uint8"}
240         RegisterTestingT(t)
241         // prepare context
242         testCtx := new(context)
243         testCtx.packageName = "test-package-name"
244
245         // prepare input/output output files
246         inputData, err := readFile("testdata/acl.api.json")
247         Expect(err).ShouldNot(HaveOccurred())
248         inFile, err := parseJSON(inputData)
249         Expect(err).ShouldNot(HaveOccurred())
250         Expect(inFile).ToNot(BeNil())
251
252         // test types
253         types := inFile.Map("types")
254         fields := make([]string, 0)
255         for i := 0; i < types.Len(); i++ {
256                 for j := 0; j < types.At(i).Len(); j++ {
257                         field := types.At(i).At(j)
258                         if field.GetType() == jsongo.TypeArray {
259                                 err := processMessageField(testCtx, &fields, field, false)
260                                 Expect(err).ShouldNot(HaveOccurred())
261                                 Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1]))
262                         }
263                 }
264         }
265 }
266
267 func TestGenerateMessageFieldMessages(t *testing.T) {
268         // expected results according to acl.api.json in testdata
269         expectedFields := []string{"\tMajor uint32", "\tMinor uint32", "\tRetval int32",
270                 "\tVpePid uint32", "\tACLIndex uint32", "\tTag []byte   `struc:\"[64]byte\"`",
271                 "\tCount uint32"}
272         RegisterTestingT(t)
273         // prepare context
274         testCtx := new(context)
275         testCtx.packageName = "test-package-name"
276
277         // prepare input/output output files
278         inputData, err := readFile("testdata/acl.api.json")
279         Expect(err).ShouldNot(HaveOccurred())
280         inFile, err := parseJSON(inputData)
281         Expect(err).ShouldNot(HaveOccurred())
282         Expect(inFile).ToNot(BeNil())
283
284         // test message fields
285         messages := inFile.Map("messages")
286         customIndex := 0
287         fields := make([]string, 0)
288         for i := 0; i < messages.Len(); i++ {
289                 for j := 0; j < messages.At(i).Len(); j++ {
290                         field := messages.At(i).At(j)
291                         if field.GetType() == jsongo.TypeArray {
292                                 specificFieldName := field.At(1).Get().(string)
293                                 if specificFieldName == "crc" || specificFieldName == "_vl_msg_id" ||
294                                         specificFieldName == "client_index" || specificFieldName == "context" {
295                                         continue
296                                 }
297                                 err := processMessageField(testCtx, &fields, field, false)
298                                 Expect(err).ShouldNot(HaveOccurred())
299                                 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
300                                 customIndex++
301                                 if customIndex >= len(expectedFields) {
302                                         // there is too much fields now for one UT...
303                                         return
304                                 }
305                         }
306                 }
307         }
308 }
309
310 func TestGeneratePackageHeader(t *testing.T) {
311         RegisterTestingT(t)
312         // prepare context
313         testCtx := new(context)
314         testCtx.packageName = "test-package-name"
315
316         // prepare input/output output files
317         inputData, err := readFile("testdata/acl.api.json")
318         Expect(err).ShouldNot(HaveOccurred())
319         inFile, err := parseJSON(inputData)
320         Expect(err).ShouldNot(HaveOccurred())
321         outDir := "test_output_directory"
322         outFile, err := os.Create(outDir)
323         Expect(err).ShouldNot(HaveOccurred())
324         defer os.RemoveAll(outDir)
325         // prepare writer
326         writer := bufio.NewWriter(outFile)
327         Expect(writer.Buffered()).To(BeZero())
328         genPackageComment(testCtx, writer, inFile)
329         Expect(writer.Buffered()).ToNot(BeZero())
330 }
331
332 func TestGenerateMessageCommentType(t *testing.T) {
333         RegisterTestingT(t)
334         // prepare context
335         testCtx := new(context)
336         testCtx.packageName = "test-package-name"
337         testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
338
339         outDir := "test_output_directory"
340         outFile, err := os.Create(outDir)
341         Expect(err).ShouldNot(HaveOccurred())
342         writer := bufio.NewWriter(outFile)
343         defer os.RemoveAll(outDir)
344         Expect(writer.Buffered()).To(BeZero())
345         generateMessageComment(testCtx, writer, "test-struct", "msg-name", true)
346         Expect(writer.Buffered()).ToNot(BeZero())
347 }
348
349 func TestGenerateMessageCommentMessage(t *testing.T) {
350         RegisterTestingT(t)
351         // prepare context
352         testCtx := new(context)
353         testCtx.packageName = "test-package-name"
354         testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
355
356         outDir := "test_output_directory"
357         outFile, err := os.Create(outDir)
358         Expect(err).ShouldNot(HaveOccurred())
359         writer := bufio.NewWriter(outFile)
360         defer os.RemoveAll(outDir)
361         Expect(writer.Buffered()).To(BeZero())
362         generateMessageComment(testCtx, writer, "test-struct", "msg-name", false)
363         Expect(writer.Buffered()).ToNot(BeZero())
364 }
365
366 func TestGenerateMessageNameGetter(t *testing.T) {
367         RegisterTestingT(t)
368         outDir := "test_output_directory"
369         outFile, err := os.Create(outDir)
370         Expect(err).ShouldNot(HaveOccurred())
371         writer := bufio.NewWriter(outFile)
372         defer os.RemoveAll(outDir)
373         Expect(writer.Buffered()).To(BeZero())
374         generateMessageNameGetter(writer, "test-struct", "msg-name")
375         Expect(writer.Buffered()).ToNot(BeZero())
376 }
377
378 func TestGenerateTypeNameGetter(t *testing.T) {
379         RegisterTestingT(t)
380         outDir := "test_output_directory"
381         outFile, err := os.Create(outDir)
382         Expect(err).ShouldNot(HaveOccurred())
383         writer := bufio.NewWriter(outFile)
384         defer os.RemoveAll(outDir)
385         Expect(writer.Buffered()).To(BeZero())
386         generateTypeNameGetter(writer, "test-struct", "msg-name")
387         Expect(writer.Buffered()).ToNot(BeZero())
388 }
389
390 func TestGenerateCrcGetter(t *testing.T) {
391         RegisterTestingT(t)
392         outDir := "test_output_directory"
393         outFile, err := os.Create(outDir)
394         Expect(err).ShouldNot(HaveOccurred())
395         writer := bufio.NewWriter(outFile)
396         defer os.RemoveAll(outDir)
397         Expect(writer.Buffered()).To(BeZero())
398         generateCrcGetter(writer, "test-struct", "msg-name")
399         Expect(writer.Buffered()).ToNot(BeZero())
400 }
401
402 func TestTranslateVppType(t *testing.T) {
403         RegisterTestingT(t)
404         context := new(context)
405         typesToTranslate := []string{"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f64"}
406         expected := []string{"uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "int64", "float64"}
407         var translated []string
408         for _, value := range typesToTranslate {
409                 translated = append(translated, convertToGoType(context, value, false))
410         }
411         for index, value := range expected {
412                 Expect(value).To(BeEquivalentTo(translated[index]))
413         }
414
415 }
416
417 func TestTranslateVppTypeArray(t *testing.T) {
418         RegisterTestingT(t)
419         context := new(context)
420         translated := convertToGoType(context, "u8", true)
421         Expect(translated).To(BeEquivalentTo("byte"))
422 }
423
424 func TestTranslateVppUnknownType(t *testing.T) {
425         defer func() {
426                 if recovery := recover(); recovery != nil {
427                         t.Logf("Recovered from panic: %v", recovery)
428                 }
429         }()
430         context := new(context)
431         convertToGoType(context, "?", false)
432 }
433
434 func TestCamelCase(t *testing.T) {
435         RegisterTestingT(t)
436         // test camel case functionality
437         expected := "allYourBaseAreBelongToUs"
438         result := camelCaseName("all_your_base_are_belong_to_us")
439         Expect(expected).To(BeEquivalentTo(result))
440         // test underscore
441         expected = "_"
442         result = camelCaseName(expected)
443         Expect(expected).To(BeEquivalentTo(result))
444         // test all lower
445         expected = "lower"
446         result = camelCaseName(expected)
447         Expect(expected).To(BeEquivalentTo(result))
448 }
449
450 func TestCommonInitialisms(t *testing.T) {
451         RegisterTestingT(t)
452
453         for key, value := range commonInitialisms {
454                 Expect(value).ShouldNot(BeFalse())
455                 Expect(key).ShouldNot(BeEmpty())
456         }
457 }
458 */