b1d4d703af8bfb4f6a6f021bba608137aac7ae7c
[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 TestGenerateFromFileACL(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 TestGenerateFromFileIP(t *testing.T) {
66         RegisterTestingT(t)
67
68         // remove directory created during test
69         defer os.RemoveAll(testOutputDir)
70
71         opts := Options{OutputDir: testOutputDir}
72         err := GenerateFromFile("vppapi/testdata/ip.api.json", opts)
73         Expect(err).ShouldNot(HaveOccurred())
74         fileInfo, err := os.Stat(testOutputDir + "/ip/ip.ba.go")
75         Expect(err).ShouldNot(HaveOccurred())
76         Expect(fileInfo.IsDir()).To(BeFalse())
77         Expect(fileInfo.Name()).To(BeEquivalentTo("ip.ba.go"))
78 }
79
80 func TestGenerateFromFileInputError(t *testing.T) {
81         RegisterTestingT(t)
82
83         opts := Options{OutputDir: testOutputDir}
84         err := GenerateFromFile("vppapi/testdata/nonexisting.json", opts)
85         Expect(err).Should(HaveOccurred())
86         Expect(err.Error()).To(ContainSubstring("unsupported"))
87 }
88
89 func TestGenerateFromFileReadJsonError(t *testing.T) {
90         RegisterTestingT(t)
91
92         opts := Options{OutputDir: testOutputDir}
93         err := GenerateFromFile("vppapi/testdata/input-read-json-error.json", opts)
94         Expect(err).Should(HaveOccurred())
95         Expect(err.Error()).To(ContainSubstring("unsupported"))
96 }
97
98 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
99         RegisterTestingT(t)
100
101         // generate package throws panic, recover after it
102         defer func() {
103                 if recovery := recover(); recovery != nil {
104                         t.Logf("Recovered from panic: %v", recovery)
105                 }
106                 os.RemoveAll(testOutputDir)
107         }()
108
109         opts := Options{OutputDir: testOutputDir}
110         err := GenerateFromFile("vppapi/testdata/input-generate-error.json", opts)
111         Expect(err).Should(HaveOccurred())
112 }
113
114 func TestAddress(t *testing.T) {
115         RegisterTestingT(t)
116
117         addr := ip_types.AddressUnionIP4(ip_types.IP4Address{10, 20, 0, 1})
118         t.Logf("addr: %v (%#v)", addr, addr)
119
120         ip4 := addr.GetIP4()
121         t.Logf("ip4: %v", ip4)
122         addr.SetIP4(ip_types.IP4Address{192, 168, 1, 1})
123         t.Logf("ip4: %v", addr.GetIP4())
124
125         Expect(addr.GetIP4()).To(Equal(ip_types.IP4Address{192, 168, 1, 1}))
126 }
127
128 /*func TestGetContext(t *testing.T) {
129         RegisterTestingT(t)
130         outDir := "test_output_directory"
131         result, err := newContext("testdata/af_packet.api.json", outDir)
132         Expect(err).ShouldNot(HaveOccurred())
133         Expect(result).ToNot(BeNil())
134         Expect(result.outputFile).To(BeEquivalentTo(outDir + "/af_packet/af_packet.ba.go"))
135 }
136
137 func TestGetContextNoJsonFile(t *testing.T) {
138         RegisterTestingT(t)
139         outDir := "test_output_directory"
140         result, err := newContext("testdata/input.txt", outDir)
141         Expect(err).Should(HaveOccurred())
142         Expect(err.Error()).To(ContainSubstring("invalid input file name"))
143         Expect(result).To(BeNil())
144 }
145
146 func TestGetContextInterfaceJson(t *testing.T) {
147         RegisterTestingT(t)
148         outDir := "test_output_directory"
149         result, err := newContext("testdata/ip.api.json", outDir)
150         Expect(err).ShouldNot(HaveOccurred())
151         Expect(result).ToNot(BeNil())
152         Expect(result.outputFile)
153         Expect(result.outputFile).To(BeEquivalentTo(outDir + "/ip/ip.ba.go"))
154 }*/
155
156 /*func TestGeneratePackage(t *testing.T) {
157         RegisterTestingT(t)
158         // prepare context
159         testCtx := new(GenFile)
160         testCtx.packageName = "test-package-name"
161
162         // prepare input/output output files
163         inputData, err := ioutil.ReadFile("testdata/ip.api.json")
164         Expect(err).ShouldNot(HaveOccurred())
165         jsonRoot, err := parseInputJSON(inputData)
166         Expect(err).ShouldNot(HaveOccurred())
167         testCtx.file, err = parseModule(testCtx, jsonRoot)
168         Expect(err).ShouldNot(HaveOccurred())
169         outDir := "test_output_directory"
170         outFile, err := os.Create(outDir)
171         Expect(err).ShouldNot(HaveOccurred())
172         defer os.RemoveAll(outDir)
173
174         // prepare writer
175         writer := bufio.NewWriter(outFile)
176         Expect(writer.Buffered()).To(BeZero())
177         err = GenerateFileBinapi(testCtx, writer)
178         Expect(err).ShouldNot(HaveOccurred())
179 }
180
181 func TestGenerateMessageType(t *testing.T) {
182         RegisterTestingT(t)
183         // prepare context
184         testCtx := new(GenFile)
185         testCtx.packageName = "test-package-name"
186
187         // prepare input/output output files
188         inputData, err := ioutil.ReadFile("testdata/ip.api.json")
189         Expect(err).ShouldNot(HaveOccurred())
190         jsonRoot, err := parseInputJSON(inputData)
191         Expect(err).ShouldNot(HaveOccurred())
192         outDir := "test_output_directory"
193         outFile, err := os.Create(outDir)
194         Expect(err).ShouldNot(HaveOccurred())
195         testCtx.file, err = parseModule(testCtx, jsonRoot)
196         Expect(err).ShouldNot(HaveOccurred())
197         defer os.RemoveAll(outDir)
198
199         // prepare writer
200         writer := bufio.NewWriter(outFile)
201
202         for _, msg := range testCtx.file.Messages {
203                 genMessage(testCtx, writer, &msg)
204                 Expect(writer.Buffered()).ToNot(BeZero())
205         }
206 }*/
207
208 /*func TestGenerateMessageName(t *testing.T) {
209         RegisterTestingT(t)
210         // prepare context
211         testCtx := new(context)
212         testCtx.packageName = "test-package-name"
213
214         // prepare input/output output files
215         inputData, err := readFile("testdata/ip.api.json")
216         Expect(err).ShouldNot(HaveOccurred())
217         testCtx.inputBuff = bytes.NewBuffer(inputData)
218         inFile, _ := parseJSON(inputData)
219         outDir := "test_output_directory"
220         outFile, err := os.Create(outDir)
221         Expect(err).ShouldNot(HaveOccurred())
222         defer os.RemoveAll(outDir)
223
224         // prepare writer
225         writer := bufio.NewWriter(outFile)
226
227         types := inFile.Map("types")
228         Expect(types.Len()).To(BeEquivalentTo(1))
229         for i := 0; i < types.Len(); i++ {
230                 typ := types.At(i)
231                 Expect(writer.Buffered()).To(BeZero())
232                 err := genMessage(testCtx, writer, typ, false)
233                 Expect(err).ShouldNot(HaveOccurred())
234                 Expect(writer.Buffered()).ToNot(BeZero())
235
236         }
237 }
238
239 func TestGenerateMessageFieldTypes(t *testing.T) {
240         // expected results according to acl.api.json in testdata
241         expectedTypes := []string{
242                 "\tIsPermit uint8",
243                 "\tIsIpv6 uint8",
244                 "\tSrcIPAddr []byte     `struc:\"[16]byte\"`",
245                 "\tSrcIPPrefixLen uint8",
246                 "\tDstIPAddr []byte     `struc:\"[16]byte\"`",
247                 "\tDstIPPrefixLen uint8",
248                 "\tProto uint8",
249                 "\tSrcportOrIcmptypeFirst uint16",
250                 "\tSrcportOrIcmptypeLast uint16",
251                 "\tDstportOrIcmpcodeFirst uint16",
252                 "\tDstportOrIcmpcodeLast uint16",
253                 "\tTCPFlagsMask uint8",
254                 "\tTCPFlagsValue uint8"}
255         RegisterTestingT(t)
256         // prepare context
257         testCtx := new(context)
258         testCtx.packageName = "test-package-name"
259
260         // prepare input/output output files
261         inputData, err := readFile("testdata/acl.api.json")
262         Expect(err).ShouldNot(HaveOccurred())
263         inFile, err := parseJSON(inputData)
264         Expect(err).ShouldNot(HaveOccurred())
265         Expect(inFile).ToNot(BeNil())
266
267         // test types
268         types := inFile.Map("types")
269         fields := make([]string, 0)
270         for i := 0; i < types.Len(); i++ {
271                 for j := 0; j < types.At(i).Len(); j++ {
272                         field := types.At(i).At(j)
273                         if field.GetType() == jsongo.TypeArray {
274                                 err := processMessageField(testCtx, &fields, field, false)
275                                 Expect(err).ShouldNot(HaveOccurred())
276                                 Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1]))
277                         }
278                 }
279         }
280 }
281
282 func TestGenerateMessageFieldMessages(t *testing.T) {
283         // expected results according to acl.api.json in testdata
284         expectedFields := []string{"\tMajor uint32", "\tMinor uint32", "\tRetval int32",
285                 "\tVpePid uint32", "\tACLIndex uint32", "\tTag []byte   `struc:\"[64]byte\"`",
286                 "\tCount uint32"}
287         RegisterTestingT(t)
288         // prepare context
289         testCtx := new(context)
290         testCtx.packageName = "test-package-name"
291
292         // prepare input/output output files
293         inputData, err := readFile("testdata/acl.api.json")
294         Expect(err).ShouldNot(HaveOccurred())
295         inFile, err := parseJSON(inputData)
296         Expect(err).ShouldNot(HaveOccurred())
297         Expect(inFile).ToNot(BeNil())
298
299         // test message fields
300         messages := inFile.Map("messages")
301         customIndex := 0
302         fields := make([]string, 0)
303         for i := 0; i < messages.Len(); i++ {
304                 for j := 0; j < messages.At(i).Len(); j++ {
305                         field := messages.At(i).At(j)
306                         if field.GetType() == jsongo.TypeArray {
307                                 specificFieldName := field.At(1).Get().(string)
308                                 if specificFieldName == "crc" || specificFieldName == "_vl_msg_id" ||
309                                         specificFieldName == "client_index" || specificFieldName == "context" {
310                                         continue
311                                 }
312                                 err := processMessageField(testCtx, &fields, field, false)
313                                 Expect(err).ShouldNot(HaveOccurred())
314                                 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
315                                 customIndex++
316                                 if customIndex >= len(expectedFields) {
317                                         // there is too much fields now for one UT...
318                                         return
319                                 }
320                         }
321                 }
322         }
323 }
324
325 func TestGeneratePackageHeader(t *testing.T) {
326         RegisterTestingT(t)
327         // prepare context
328         testCtx := new(context)
329         testCtx.packageName = "test-package-name"
330
331         // prepare input/output output files
332         inputData, err := readFile("testdata/acl.api.json")
333         Expect(err).ShouldNot(HaveOccurred())
334         inFile, err := parseJSON(inputData)
335         Expect(err).ShouldNot(HaveOccurred())
336         outDir := "test_output_directory"
337         outFile, err := os.Create(outDir)
338         Expect(err).ShouldNot(HaveOccurred())
339         defer os.RemoveAll(outDir)
340         // prepare writer
341         writer := bufio.NewWriter(outFile)
342         Expect(writer.Buffered()).To(BeZero())
343         genPackageComment(testCtx, writer, inFile)
344         Expect(writer.Buffered()).ToNot(BeZero())
345 }
346
347 func TestGenerateMessageCommentType(t *testing.T) {
348         RegisterTestingT(t)
349         // prepare context
350         testCtx := new(context)
351         testCtx.packageName = "test-package-name"
352         testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
353
354         outDir := "test_output_directory"
355         outFile, err := os.Create(outDir)
356         Expect(err).ShouldNot(HaveOccurred())
357         writer := bufio.NewWriter(outFile)
358         defer os.RemoveAll(outDir)
359         Expect(writer.Buffered()).To(BeZero())
360         generateMessageComment(testCtx, writer, "test-struct", "msg-name", true)
361         Expect(writer.Buffered()).ToNot(BeZero())
362 }
363
364 func TestGenerateMessageCommentMessage(t *testing.T) {
365         RegisterTestingT(t)
366         // prepare context
367         testCtx := new(context)
368         testCtx.packageName = "test-package-name"
369         testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
370
371         outDir := "test_output_directory"
372         outFile, err := os.Create(outDir)
373         Expect(err).ShouldNot(HaveOccurred())
374         writer := bufio.NewWriter(outFile)
375         defer os.RemoveAll(outDir)
376         Expect(writer.Buffered()).To(BeZero())
377         generateMessageComment(testCtx, writer, "test-struct", "msg-name", false)
378         Expect(writer.Buffered()).ToNot(BeZero())
379 }
380
381 func TestGenerateMessageNameGetter(t *testing.T) {
382         RegisterTestingT(t)
383         outDir := "test_output_directory"
384         outFile, err := os.Create(outDir)
385         Expect(err).ShouldNot(HaveOccurred())
386         writer := bufio.NewWriter(outFile)
387         defer os.RemoveAll(outDir)
388         Expect(writer.Buffered()).To(BeZero())
389         generateMessageNameGetter(writer, "test-struct", "msg-name")
390         Expect(writer.Buffered()).ToNot(BeZero())
391 }
392
393 func TestGenerateTypeNameGetter(t *testing.T) {
394         RegisterTestingT(t)
395         outDir := "test_output_directory"
396         outFile, err := os.Create(outDir)
397         Expect(err).ShouldNot(HaveOccurred())
398         writer := bufio.NewWriter(outFile)
399         defer os.RemoveAll(outDir)
400         Expect(writer.Buffered()).To(BeZero())
401         generateTypeNameGetter(writer, "test-struct", "msg-name")
402         Expect(writer.Buffered()).ToNot(BeZero())
403 }
404
405 func TestGenerateCrcGetter(t *testing.T) {
406         RegisterTestingT(t)
407         outDir := "test_output_directory"
408         outFile, err := os.Create(outDir)
409         Expect(err).ShouldNot(HaveOccurred())
410         writer := bufio.NewWriter(outFile)
411         defer os.RemoveAll(outDir)
412         Expect(writer.Buffered()).To(BeZero())
413         generateCrcGetter(writer, "test-struct", "msg-name")
414         Expect(writer.Buffered()).ToNot(BeZero())
415 }
416
417 func TestTranslateVppType(t *testing.T) {
418         RegisterTestingT(t)
419         context := new(context)
420         typesToTranslate := []string{"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f64"}
421         expected := []string{"uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "int64", "float64"}
422         var translated []string
423         for _, value := range typesToTranslate {
424                 translated = append(translated, convertToGoType(context, value, false))
425         }
426         for index, value := range expected {
427                 Expect(value).To(BeEquivalentTo(translated[index]))
428         }
429
430 }
431
432 func TestTranslateVppTypeArray(t *testing.T) {
433         RegisterTestingT(t)
434         context := new(context)
435         translated := convertToGoType(context, "u8", true)
436         Expect(translated).To(BeEquivalentTo("byte"))
437 }
438
439 func TestTranslateVppUnknownType(t *testing.T) {
440         defer func() {
441                 if recovery := recover(); recovery != nil {
442                         t.Logf("Recovered from panic: %v", recovery)
443                 }
444         }()
445         context := new(context)
446         convertToGoType(context, "?", false)
447 }
448
449 func TestCamelCase(t *testing.T) {
450         RegisterTestingT(t)
451         // test camel case functionality
452         expected := "allYourBaseAreBelongToUs"
453         result := camelCaseName("all_your_base_are_belong_to_us")
454         Expect(expected).To(BeEquivalentTo(result))
455         // test underscore
456         expected = "_"
457         result = camelCaseName(expected)
458         Expect(expected).To(BeEquivalentTo(result))
459         // test all lower
460         expected = "lower"
461         result = camelCaseName(expected)
462         Expect(expected).To(BeEquivalentTo(result))
463 }
464
465 func TestCommonInitialisms(t *testing.T) {
466         RegisterTestingT(t)
467
468         for key, value := range commonInitialisms {
469                 Expect(value).ShouldNot(BeFalse())
470                 Expect(key).ShouldNot(BeEmpty())
471         }
472 }
473 */