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 TestGenerateFromFile(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 TestGenerateFromFileInputError(t *testing.T) {
68 opts := Options{OutputDir: testOutputDir}
69 err := GenerateFromFile("vppapi/testdata/nonexisting.json", opts)
70 Expect(err).Should(HaveOccurred())
71 Expect(err.Error()).To(ContainSubstring("unsupported"))
74 func TestGenerateFromFileReadJsonError(t *testing.T) {
77 opts := Options{OutputDir: testOutputDir}
78 err := GenerateFromFile("vppapi/testdata/input-read-json-error.json", opts)
79 Expect(err).Should(HaveOccurred())
80 Expect(err.Error()).To(ContainSubstring("unsupported"))
83 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
86 // generate package throws panic, recover after it
88 if recovery := recover(); recovery != nil {
89 t.Logf("Recovered from panic: %v", recovery)
91 os.RemoveAll(testOutputDir)
94 opts := Options{OutputDir: testOutputDir}
95 err := GenerateFromFile("vppapi/testdata/input-generate-error.json", opts)
96 Expect(err).Should(HaveOccurred())
99 func TestAddress(t *testing.T) {
102 addr := ip_types.AddressUnionIP4(ip_types.IP4Address{10, 20, 0, 1})
103 t.Logf("addr: %v (%#v)", addr, addr)
106 t.Logf("ip4: %v", ip4)
107 addr.SetIP4(ip_types.IP4Address{192, 168, 1, 1})
108 t.Logf("ip4: %v", addr.GetIP4())
110 Expect(addr.GetIP4()).To(Equal(ip_types.IP4Address{192, 168, 1, 1}))
113 /*func TestGetContext(t *testing.T) {
115 outDir := "test_output_directory"
116 result, err := newContext("testdata/af_packet.api.json", outDir)
117 Expect(err).ShouldNot(HaveOccurred())
118 Expect(result).ToNot(BeNil())
119 Expect(result.outputFile).To(BeEquivalentTo(outDir + "/af_packet/af_packet.ba.go"))
122 func TestGetContextNoJsonFile(t *testing.T) {
124 outDir := "test_output_directory"
125 result, err := newContext("testdata/input.txt", outDir)
126 Expect(err).Should(HaveOccurred())
127 Expect(err.Error()).To(ContainSubstring("invalid input file name"))
128 Expect(result).To(BeNil())
131 func TestGetContextInterfaceJson(t *testing.T) {
133 outDir := "test_output_directory"
134 result, err := newContext("testdata/ip.api.json", outDir)
135 Expect(err).ShouldNot(HaveOccurred())
136 Expect(result).ToNot(BeNil())
137 Expect(result.outputFile)
138 Expect(result.outputFile).To(BeEquivalentTo(outDir + "/ip/ip.ba.go"))
141 /*func TestGeneratePackage(t *testing.T) {
144 testCtx := new(GenFile)
145 testCtx.packageName = "test-package-name"
147 // prepare input/output output files
148 inputData, err := ioutil.ReadFile("testdata/ip.api.json")
149 Expect(err).ShouldNot(HaveOccurred())
150 jsonRoot, err := parseInputJSON(inputData)
151 Expect(err).ShouldNot(HaveOccurred())
152 testCtx.file, err = parseModule(testCtx, jsonRoot)
153 Expect(err).ShouldNot(HaveOccurred())
154 outDir := "test_output_directory"
155 outFile, err := os.Create(outDir)
156 Expect(err).ShouldNot(HaveOccurred())
157 defer os.RemoveAll(outDir)
160 writer := bufio.NewWriter(outFile)
161 Expect(writer.Buffered()).To(BeZero())
162 err = GenerateFileBinapi(testCtx, writer)
163 Expect(err).ShouldNot(HaveOccurred())
166 func TestGenerateMessageType(t *testing.T) {
169 testCtx := new(GenFile)
170 testCtx.packageName = "test-package-name"
172 // prepare input/output output files
173 inputData, err := ioutil.ReadFile("testdata/ip.api.json")
174 Expect(err).ShouldNot(HaveOccurred())
175 jsonRoot, err := parseInputJSON(inputData)
176 Expect(err).ShouldNot(HaveOccurred())
177 outDir := "test_output_directory"
178 outFile, err := os.Create(outDir)
179 Expect(err).ShouldNot(HaveOccurred())
180 testCtx.file, err = parseModule(testCtx, jsonRoot)
181 Expect(err).ShouldNot(HaveOccurred())
182 defer os.RemoveAll(outDir)
185 writer := bufio.NewWriter(outFile)
187 for _, msg := range testCtx.file.Messages {
188 genMessage(testCtx, writer, &msg)
189 Expect(writer.Buffered()).ToNot(BeZero())
193 /*func TestGenerateMessageName(t *testing.T) {
196 testCtx := new(context)
197 testCtx.packageName = "test-package-name"
199 // prepare input/output output files
200 inputData, err := readFile("testdata/ip.api.json")
201 Expect(err).ShouldNot(HaveOccurred())
202 testCtx.inputBuff = bytes.NewBuffer(inputData)
203 inFile, _ := parseJSON(inputData)
204 outDir := "test_output_directory"
205 outFile, err := os.Create(outDir)
206 Expect(err).ShouldNot(HaveOccurred())
207 defer os.RemoveAll(outDir)
210 writer := bufio.NewWriter(outFile)
212 types := inFile.Map("types")
213 Expect(types.Len()).To(BeEquivalentTo(1))
214 for i := 0; i < types.Len(); i++ {
216 Expect(writer.Buffered()).To(BeZero())
217 err := genMessage(testCtx, writer, typ, false)
218 Expect(err).ShouldNot(HaveOccurred())
219 Expect(writer.Buffered()).ToNot(BeZero())
224 func TestGenerateMessageFieldTypes(t *testing.T) {
225 // expected results according to acl.api.json in testdata
226 expectedTypes := []string{
229 "\tSrcIPAddr []byte `struc:\"[16]byte\"`",
230 "\tSrcIPPrefixLen uint8",
231 "\tDstIPAddr []byte `struc:\"[16]byte\"`",
232 "\tDstIPPrefixLen uint8",
234 "\tSrcportOrIcmptypeFirst uint16",
235 "\tSrcportOrIcmptypeLast uint16",
236 "\tDstportOrIcmpcodeFirst uint16",
237 "\tDstportOrIcmpcodeLast uint16",
238 "\tTCPFlagsMask uint8",
239 "\tTCPFlagsValue uint8"}
242 testCtx := new(context)
243 testCtx.packageName = "test-package-name"
245 // prepare input/output output files
246 inputData, err := readFile("testdata/acl.api.json")
247 Expect(err).ShouldNot(HaveOccurred())
248 inFile, err := parseJSON(inputData)
249 Expect(err).ShouldNot(HaveOccurred())
250 Expect(inFile).ToNot(BeNil())
253 types := inFile.Map("types")
254 fields := make([]string, 0)
255 for i := 0; i < types.Len(); i++ {
256 for j := 0; j < types.At(i).Len(); j++ {
257 field := types.At(i).At(j)
258 if field.GetType() == jsongo.TypeArray {
259 err := processMessageField(testCtx, &fields, field, false)
260 Expect(err).ShouldNot(HaveOccurred())
261 Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1]))
267 func TestGenerateMessageFieldMessages(t *testing.T) {
268 // expected results according to acl.api.json in testdata
269 expectedFields := []string{"\tMajor uint32", "\tMinor uint32", "\tRetval int32",
270 "\tVpePid uint32", "\tACLIndex uint32", "\tTag []byte `struc:\"[64]byte\"`",
274 testCtx := new(context)
275 testCtx.packageName = "test-package-name"
277 // prepare input/output output files
278 inputData, err := readFile("testdata/acl.api.json")
279 Expect(err).ShouldNot(HaveOccurred())
280 inFile, err := parseJSON(inputData)
281 Expect(err).ShouldNot(HaveOccurred())
282 Expect(inFile).ToNot(BeNil())
284 // test message fields
285 messages := inFile.Map("messages")
287 fields := make([]string, 0)
288 for i := 0; i < messages.Len(); i++ {
289 for j := 0; j < messages.At(i).Len(); j++ {
290 field := messages.At(i).At(j)
291 if field.GetType() == jsongo.TypeArray {
292 specificFieldName := field.At(1).Get().(string)
293 if specificFieldName == "crc" || specificFieldName == "_vl_msg_id" ||
294 specificFieldName == "client_index" || specificFieldName == "context" {
297 err := processMessageField(testCtx, &fields, field, false)
298 Expect(err).ShouldNot(HaveOccurred())
299 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
301 if customIndex >= len(expectedFields) {
302 // there is too much fields now for one UT...
310 func TestGeneratePackageHeader(t *testing.T) {
313 testCtx := new(context)
314 testCtx.packageName = "test-package-name"
316 // prepare input/output output files
317 inputData, err := readFile("testdata/acl.api.json")
318 Expect(err).ShouldNot(HaveOccurred())
319 inFile, err := parseJSON(inputData)
320 Expect(err).ShouldNot(HaveOccurred())
321 outDir := "test_output_directory"
322 outFile, err := os.Create(outDir)
323 Expect(err).ShouldNot(HaveOccurred())
324 defer os.RemoveAll(outDir)
326 writer := bufio.NewWriter(outFile)
327 Expect(writer.Buffered()).To(BeZero())
328 genPackageComment(testCtx, writer, inFile)
329 Expect(writer.Buffered()).ToNot(BeZero())
332 func TestGenerateMessageCommentType(t *testing.T) {
335 testCtx := new(context)
336 testCtx.packageName = "test-package-name"
337 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
339 outDir := "test_output_directory"
340 outFile, err := os.Create(outDir)
341 Expect(err).ShouldNot(HaveOccurred())
342 writer := bufio.NewWriter(outFile)
343 defer os.RemoveAll(outDir)
344 Expect(writer.Buffered()).To(BeZero())
345 generateMessageComment(testCtx, writer, "test-struct", "msg-name", true)
346 Expect(writer.Buffered()).ToNot(BeZero())
349 func TestGenerateMessageCommentMessage(t *testing.T) {
352 testCtx := new(context)
353 testCtx.packageName = "test-package-name"
354 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
356 outDir := "test_output_directory"
357 outFile, err := os.Create(outDir)
358 Expect(err).ShouldNot(HaveOccurred())
359 writer := bufio.NewWriter(outFile)
360 defer os.RemoveAll(outDir)
361 Expect(writer.Buffered()).To(BeZero())
362 generateMessageComment(testCtx, writer, "test-struct", "msg-name", false)
363 Expect(writer.Buffered()).ToNot(BeZero())
366 func TestGenerateMessageNameGetter(t *testing.T) {
368 outDir := "test_output_directory"
369 outFile, err := os.Create(outDir)
370 Expect(err).ShouldNot(HaveOccurred())
371 writer := bufio.NewWriter(outFile)
372 defer os.RemoveAll(outDir)
373 Expect(writer.Buffered()).To(BeZero())
374 generateMessageNameGetter(writer, "test-struct", "msg-name")
375 Expect(writer.Buffered()).ToNot(BeZero())
378 func TestGenerateTypeNameGetter(t *testing.T) {
380 outDir := "test_output_directory"
381 outFile, err := os.Create(outDir)
382 Expect(err).ShouldNot(HaveOccurred())
383 writer := bufio.NewWriter(outFile)
384 defer os.RemoveAll(outDir)
385 Expect(writer.Buffered()).To(BeZero())
386 generateTypeNameGetter(writer, "test-struct", "msg-name")
387 Expect(writer.Buffered()).ToNot(BeZero())
390 func TestGenerateCrcGetter(t *testing.T) {
392 outDir := "test_output_directory"
393 outFile, err := os.Create(outDir)
394 Expect(err).ShouldNot(HaveOccurred())
395 writer := bufio.NewWriter(outFile)
396 defer os.RemoveAll(outDir)
397 Expect(writer.Buffered()).To(BeZero())
398 generateCrcGetter(writer, "test-struct", "msg-name")
399 Expect(writer.Buffered()).ToNot(BeZero())
402 func TestTranslateVppType(t *testing.T) {
404 context := new(context)
405 typesToTranslate := []string{"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f64"}
406 expected := []string{"uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "int64", "float64"}
407 var translated []string
408 for _, value := range typesToTranslate {
409 translated = append(translated, convertToGoType(context, value, false))
411 for index, value := range expected {
412 Expect(value).To(BeEquivalentTo(translated[index]))
417 func TestTranslateVppTypeArray(t *testing.T) {
419 context := new(context)
420 translated := convertToGoType(context, "u8", true)
421 Expect(translated).To(BeEquivalentTo("byte"))
424 func TestTranslateVppUnknownType(t *testing.T) {
426 if recovery := recover(); recovery != nil {
427 t.Logf("Recovered from panic: %v", recovery)
430 context := new(context)
431 convertToGoType(context, "?", false)
434 func TestCamelCase(t *testing.T) {
436 // test camel case functionality
437 expected := "allYourBaseAreBelongToUs"
438 result := camelCaseName("all_your_base_are_belong_to_us")
439 Expect(expected).To(BeEquivalentTo(result))
442 result = camelCaseName(expected)
443 Expect(expected).To(BeEquivalentTo(result))
446 result = camelCaseName(expected)
447 Expect(expected).To(BeEquivalentTo(result))
450 func TestCommonInitialisms(t *testing.T) {
453 for key, value := range commonInitialisms {
454 Expect(value).ShouldNot(BeFalse())
455 Expect(key).ShouldNot(BeEmpty())