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