1 // Copyright (c) 2020 Cisco and/or its affiliates.
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:
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
21 . "github.com/onsi/gomega"
23 "git.fd.io/govpp.git/binapi/ip_types"
24 "git.fd.io/govpp.git/binapigen/vppapi"
27 const testOutputDir = "test_output_dir"
29 func GenerateFromFile(file string, opts Options) error {
30 apifile, err := vppapi.ParseFile(file)
34 gen, err := New(opts, []*vppapi.File{apifile}, nil)
38 for _, file := range gen.Files {
42 GenerateAPI(gen, file)
44 if err = gen.Generate(); err != nil {
50 func TestGenerateFromFileACL(t *testing.T) {
53 // remove directory created during test
54 defer os.RemoveAll(testOutputDir)
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"))
65 func TestGenerateFromFileIP(t *testing.T) {
68 // remove directory created during test
69 defer os.RemoveAll(testOutputDir)
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"))
80 func TestGenerateFromFileInputError(t *testing.T) {
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"))
89 func TestGenerateFromFileReadJsonError(t *testing.T) {
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"))
98 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
101 // generate package throws panic, recover after it
103 if recovery := recover(); recovery != nil {
104 t.Logf("Recovered from panic: %v", recovery)
106 os.RemoveAll(testOutputDir)
109 opts := Options{OutputDir: testOutputDir}
110 err := GenerateFromFile("vppapi/testdata/input-generate-error.json", opts)
111 Expect(err).Should(HaveOccurred())
114 func TestAddress(t *testing.T) {
117 addr := ip_types.AddressUnionIP4(ip_types.IP4Address{10, 20, 0, 1})
118 t.Logf("addr: %v (%#v)", addr, addr)
121 t.Logf("ip4: %v", ip4)
122 addr.SetIP4(ip_types.IP4Address{192, 168, 1, 1})
123 t.Logf("ip4: %v", addr.GetIP4())
125 Expect(addr.GetIP4()).To(Equal(ip_types.IP4Address{192, 168, 1, 1}))
128 /*func TestGetContext(t *testing.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"))
137 func TestGetContextNoJsonFile(t *testing.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())
146 func TestGetContextInterfaceJson(t *testing.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"))
156 /*func TestGeneratePackage(t *testing.T) {
159 testCtx := new(GenFile)
160 testCtx.packageName = "test-package-name"
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)
175 writer := bufio.NewWriter(outFile)
176 Expect(writer.Buffered()).To(BeZero())
177 err = GenerateFileBinapi(testCtx, writer)
178 Expect(err).ShouldNot(HaveOccurred())
181 func TestGenerateMessageType(t *testing.T) {
184 testCtx := new(GenFile)
185 testCtx.packageName = "test-package-name"
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)
200 writer := bufio.NewWriter(outFile)
202 for _, msg := range testCtx.file.Messages {
203 genMessage(testCtx, writer, &msg)
204 Expect(writer.Buffered()).ToNot(BeZero())
208 /*func TestGenerateMessageName(t *testing.T) {
211 testCtx := new(context)
212 testCtx.packageName = "test-package-name"
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)
225 writer := bufio.NewWriter(outFile)
227 types := inFile.Map("types")
228 Expect(types.Len()).To(BeEquivalentTo(1))
229 for i := 0; i < types.Len(); 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())
239 func TestGenerateMessageFieldTypes(t *testing.T) {
240 // expected results according to acl.api.json in testdata
241 expectedTypes := []string{
244 "\tSrcIPAddr []byte `struc:\"[16]byte\"`",
245 "\tSrcIPPrefixLen uint8",
246 "\tDstIPAddr []byte `struc:\"[16]byte\"`",
247 "\tDstIPPrefixLen uint8",
249 "\tSrcportOrIcmptypeFirst uint16",
250 "\tSrcportOrIcmptypeLast uint16",
251 "\tDstportOrIcmpcodeFirst uint16",
252 "\tDstportOrIcmpcodeLast uint16",
253 "\tTCPFlagsMask uint8",
254 "\tTCPFlagsValue uint8"}
257 testCtx := new(context)
258 testCtx.packageName = "test-package-name"
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())
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]))
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\"`",
289 testCtx := new(context)
290 testCtx.packageName = "test-package-name"
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())
299 // test message fields
300 messages := inFile.Map("messages")
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" {
312 err := processMessageField(testCtx, &fields, field, false)
313 Expect(err).ShouldNot(HaveOccurred())
314 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
316 if customIndex >= len(expectedFields) {
317 // there is too much fields now for one UT...
325 func TestGeneratePackageHeader(t *testing.T) {
328 testCtx := new(context)
329 testCtx.packageName = "test-package-name"
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)
341 writer := bufio.NewWriter(outFile)
342 Expect(writer.Buffered()).To(BeZero())
343 genPackageComment(testCtx, writer, inFile)
344 Expect(writer.Buffered()).ToNot(BeZero())
347 func TestGenerateMessageCommentType(t *testing.T) {
350 testCtx := new(context)
351 testCtx.packageName = "test-package-name"
352 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
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())
364 func TestGenerateMessageCommentMessage(t *testing.T) {
367 testCtx := new(context)
368 testCtx.packageName = "test-package-name"
369 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
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())
381 func TestGenerateMessageNameGetter(t *testing.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())
393 func TestGenerateTypeNameGetter(t *testing.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())
405 func TestGenerateCrcGetter(t *testing.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())
417 func TestTranslateVppType(t *testing.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))
426 for index, value := range expected {
427 Expect(value).To(BeEquivalentTo(translated[index]))
432 func TestTranslateVppTypeArray(t *testing.T) {
434 context := new(context)
435 translated := convertToGoType(context, "u8", true)
436 Expect(translated).To(BeEquivalentTo("byte"))
439 func TestTranslateVppUnknownType(t *testing.T) {
441 if recovery := recover(); recovery != nil {
442 t.Logf("Recovered from panic: %v", recovery)
445 context := new(context)
446 convertToGoType(context, "?", false)
449 func TestCamelCase(t *testing.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))
457 result = camelCaseName(expected)
458 Expect(expected).To(BeEquivalentTo(result))
461 result = camelCaseName(expected)
462 Expect(expected).To(BeEquivalentTo(result))
465 func TestCommonInitialisms(t *testing.T) {
468 for key, value := range commonInitialisms {
469 Expect(value).ShouldNot(BeFalse())
470 Expect(key).ShouldNot(BeEmpty())