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