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