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/binapigen/vppapi"
26 const testOutputDir = "test_output_directory"
28 func GenerateFromFile(file, outputDir string, opts Options) error {
29 apifile, err := vppapi.ParseFile(file)
34 g, err := New(opts, []*vppapi.File{apifile})
38 for _, file := range g.Files {
42 GenerateBinapi(g, file, outputDir)
43 if file.Service != nil {
44 GenerateRPC(g, file, outputDir)
48 if err = g.Generate(); err != nil {
55 func TestGenerateFromFile(t *testing.T) {
58 // remove directory created during test
59 defer os.RemoveAll(testOutputDir)
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"))
69 func TestGenerateFromFileInputError(t *testing.T) {
72 err := GenerateFromFile("vppapi/testdata/nonexisting.json", testOutputDir, Options{})
73 Expect(err).Should(HaveOccurred())
74 Expect(err.Error()).To(ContainSubstring("unsupported"))
77 func TestGenerateFromFileReadJsonError(t *testing.T) {
80 err := GenerateFromFile("vppapi/testdata/input-read-json-error.json", testOutputDir, Options{})
81 Expect(err).Should(HaveOccurred())
82 Expect(err.Error()).To(ContainSubstring("unsupported"))
85 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
88 // generate package throws panic, recover after it
90 if recovery := recover(); recovery != nil {
91 t.Logf("Recovered from panic: %v", recovery)
93 os.RemoveAll(testOutputDir)
96 err := GenerateFromFile("vppapi/testdata/input-generate-error.json", testOutputDir, Options{})
97 Expect(err).Should(HaveOccurred())
100 /*func TestGetContext(t *testing.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"))
109 func TestGetContextNoJsonFile(t *testing.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())
118 func TestGetContextInterfaceJson(t *testing.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"))
128 /*func TestGeneratePackage(t *testing.T) {
131 testCtx := new(GenFile)
132 testCtx.packageName = "test-package-name"
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)
147 writer := bufio.NewWriter(outFile)
148 Expect(writer.Buffered()).To(BeZero())
149 err = generateFileBinapi(testCtx, writer)
150 Expect(err).ShouldNot(HaveOccurred())
153 func TestGenerateMessageType(t *testing.T) {
156 testCtx := new(GenFile)
157 testCtx.packageName = "test-package-name"
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)
172 writer := bufio.NewWriter(outFile)
174 for _, msg := range testCtx.file.Messages {
175 generateMessage(testCtx, writer, &msg)
176 Expect(writer.Buffered()).ToNot(BeZero())
180 /*func TestGenerateMessageName(t *testing.T) {
183 testCtx := new(context)
184 testCtx.packageName = "test-package-name"
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)
197 writer := bufio.NewWriter(outFile)
199 types := inFile.Map("types")
200 Expect(types.Len()).To(BeEquivalentTo(1))
201 for i := 0; i < types.Len(); 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())
211 func TestGenerateMessageFieldTypes(t *testing.T) {
212 // expected results according to acl.api.json in testdata
213 expectedTypes := []string{
216 "\tSrcIPAddr []byte `struc:\"[16]byte\"`",
217 "\tSrcIPPrefixLen uint8",
218 "\tDstIPAddr []byte `struc:\"[16]byte\"`",
219 "\tDstIPPrefixLen uint8",
221 "\tSrcportOrIcmptypeFirst uint16",
222 "\tSrcportOrIcmptypeLast uint16",
223 "\tDstportOrIcmpcodeFirst uint16",
224 "\tDstportOrIcmpcodeLast uint16",
225 "\tTCPFlagsMask uint8",
226 "\tTCPFlagsValue uint8"}
229 testCtx := new(context)
230 testCtx.packageName = "test-package-name"
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())
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]))
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\"`",
261 testCtx := new(context)
262 testCtx.packageName = "test-package-name"
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())
271 // test message fields
272 messages := inFile.Map("messages")
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" {
284 err := processMessageField(testCtx, &fields, field, false)
285 Expect(err).ShouldNot(HaveOccurred())
286 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
288 if customIndex >= len(expectedFields) {
289 // there is too much fields now for one UT...
297 func TestGeneratePackageHeader(t *testing.T) {
300 testCtx := new(context)
301 testCtx.packageName = "test-package-name"
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)
313 writer := bufio.NewWriter(outFile)
314 Expect(writer.Buffered()).To(BeZero())
315 generatePackageHeader(testCtx, writer, inFile)
316 Expect(writer.Buffered()).ToNot(BeZero())
319 func TestGenerateMessageCommentType(t *testing.T) {
322 testCtx := new(context)
323 testCtx.packageName = "test-package-name"
324 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
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())
336 func TestGenerateMessageCommentMessage(t *testing.T) {
339 testCtx := new(context)
340 testCtx.packageName = "test-package-name"
341 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
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())
353 func TestGenerateMessageNameGetter(t *testing.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())
365 func TestGenerateTypeNameGetter(t *testing.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())
377 func TestGenerateCrcGetter(t *testing.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())
389 func TestTranslateVppType(t *testing.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))
398 for index, value := range expected {
399 Expect(value).To(BeEquivalentTo(translated[index]))
404 func TestTranslateVppTypeArray(t *testing.T) {
406 context := new(context)
407 translated := convertToGoType(context, "u8", true)
408 Expect(translated).To(BeEquivalentTo("byte"))
411 func TestTranslateVppUnknownType(t *testing.T) {
413 if recovery := recover(); recovery != nil {
414 t.Logf("Recovered from panic: %v", recovery)
417 context := new(context)
418 convertToGoType(context, "?", false)
421 func TestCamelCase(t *testing.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))
429 result = camelCaseName(expected)
430 Expect(expected).To(BeEquivalentTo(result))
433 result = camelCaseName(expected)
434 Expect(expected).To(BeEquivalentTo(result))
437 func TestCommonInitialisms(t *testing.T) {
440 for key, value := range commonInitialisms {
441 Expect(value).ShouldNot(BeFalse())
442 Expect(key).ShouldNot(BeEmpty())