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(apiDir, outputDir string, opts Options) error {
30 apifiles, err := vppapi.ParseDir(apiDir)
35 g, err := New(opts, apifiles)
39 for _, file := range g.Files {
43 GenerateBinapiFile(g, file, outputDir)
44 if file.Service != nil {
45 GenerateRPC(g, file, outputDir)
49 if err = g.Generate(); err != nil {
56 func TestGenerateFromFile(t *testing.T) {
59 // remove directory created during test
60 defer os.RemoveAll(testOutputDir)
62 err := GenerateFromFile("testdata/acl.api.json", testOutputDir, Options{})
63 Expect(err).ShouldNot(HaveOccurred())
64 fileInfo, err := os.Stat(testOutputDir + "/acl/acl.ba.go")
65 Expect(err).ShouldNot(HaveOccurred())
66 Expect(fileInfo.IsDir()).To(BeFalse())
67 Expect(fileInfo.Name()).To(BeEquivalentTo("acl.ba.go"))
70 func TestGenerateFromFileInputError(t *testing.T) {
73 err := GenerateFromFile("testdata/nonexisting.json", testOutputDir, Options{})
74 Expect(err).Should(HaveOccurred())
75 Expect(err.Error()).To(ContainSubstring("invalid input file name"))
78 func TestGenerateFromFileReadJsonError(t *testing.T) {
81 err := GenerateFromFile("testdata/input-read-json-error.json", testOutputDir, Options{})
82 Expect(err).Should(HaveOccurred())
83 Expect(err.Error()).To(ContainSubstring("invalid input file name"))
86 func TestGenerateFromFileGeneratePackageError(t *testing.T) {
89 // generate package throws panic, recover after it
91 if recovery := recover(); recovery != nil {
92 t.Logf("Recovered from panic: %v", recovery)
94 os.RemoveAll(testOutputDir)
97 err := GenerateFromFile("testdata/input-generate-error.json", testOutputDir, Options{})
98 Expect(err).Should(HaveOccurred())
101 /*func TestGetContext(t *testing.T) {
103 outDir := "test_output_directory"
104 result, err := newContext("testdata/af_packet.api.json", outDir)
105 Expect(err).ShouldNot(HaveOccurred())
106 Expect(result).ToNot(BeNil())
107 Expect(result.outputFile).To(BeEquivalentTo(outDir + "/af_packet/af_packet.ba.go"))
110 func TestGetContextNoJsonFile(t *testing.T) {
112 outDir := "test_output_directory"
113 result, err := newContext("testdata/input.txt", outDir)
114 Expect(err).Should(HaveOccurred())
115 Expect(err.Error()).To(ContainSubstring("invalid input file name"))
116 Expect(result).To(BeNil())
119 func TestGetContextInterfaceJson(t *testing.T) {
121 outDir := "test_output_directory"
122 result, err := newContext("testdata/ip.api.json", outDir)
123 Expect(err).ShouldNot(HaveOccurred())
124 Expect(result).ToNot(BeNil())
125 Expect(result.outputFile)
126 Expect(result.outputFile).To(BeEquivalentTo(outDir + "/ip/ip.ba.go"))
129 /*func TestGeneratePackage(t *testing.T) {
132 testCtx := new(GenFile)
133 testCtx.packageName = "test-package-name"
135 // prepare input/output output files
136 inputData, err := ioutil.ReadFile("testdata/ip.api.json")
137 Expect(err).ShouldNot(HaveOccurred())
138 jsonRoot, err := parseInputJSON(inputData)
139 Expect(err).ShouldNot(HaveOccurred())
140 testCtx.file, err = parseModule(testCtx, jsonRoot)
141 Expect(err).ShouldNot(HaveOccurred())
142 outDir := "test_output_directory"
143 outFile, err := os.Create(outDir)
144 Expect(err).ShouldNot(HaveOccurred())
145 defer os.RemoveAll(outDir)
148 writer := bufio.NewWriter(outFile)
149 Expect(writer.Buffered()).To(BeZero())
150 err = generatePackage(testCtx, writer)
151 Expect(err).ShouldNot(HaveOccurred())
154 func TestGenerateMessageType(t *testing.T) {
157 testCtx := new(GenFile)
158 testCtx.packageName = "test-package-name"
160 // prepare input/output output files
161 inputData, err := ioutil.ReadFile("testdata/ip.api.json")
162 Expect(err).ShouldNot(HaveOccurred())
163 jsonRoot, err := parseInputJSON(inputData)
164 Expect(err).ShouldNot(HaveOccurred())
165 outDir := "test_output_directory"
166 outFile, err := os.Create(outDir)
167 Expect(err).ShouldNot(HaveOccurred())
168 testCtx.file, err = parseModule(testCtx, jsonRoot)
169 Expect(err).ShouldNot(HaveOccurred())
170 defer os.RemoveAll(outDir)
173 writer := bufio.NewWriter(outFile)
175 for _, msg := range testCtx.file.Messages {
176 generateMessage(testCtx, writer, &msg)
177 Expect(writer.Buffered()).ToNot(BeZero())
181 /*func TestGenerateMessageName(t *testing.T) {
184 testCtx := new(context)
185 testCtx.packageName = "test-package-name"
187 // prepare input/output output files
188 inputData, err := readFile("testdata/ip.api.json")
189 Expect(err).ShouldNot(HaveOccurred())
190 testCtx.inputBuff = bytes.NewBuffer(inputData)
191 inFile, _ := parseJSON(inputData)
192 outDir := "test_output_directory"
193 outFile, err := os.Create(outDir)
194 Expect(err).ShouldNot(HaveOccurred())
195 defer os.RemoveAll(outDir)
198 writer := bufio.NewWriter(outFile)
200 types := inFile.Map("types")
201 Expect(types.Len()).To(BeEquivalentTo(1))
202 for i := 0; i < types.Len(); i++ {
204 Expect(writer.Buffered()).To(BeZero())
205 err := generateMessage(testCtx, writer, typ, false)
206 Expect(err).ShouldNot(HaveOccurred())
207 Expect(writer.Buffered()).ToNot(BeZero())
212 func TestGenerateMessageFieldTypes(t *testing.T) {
213 // expected results according to acl.api.json in testdata
214 expectedTypes := []string{
217 "\tSrcIPAddr []byte `struc:\"[16]byte\"`",
218 "\tSrcIPPrefixLen uint8",
219 "\tDstIPAddr []byte `struc:\"[16]byte\"`",
220 "\tDstIPPrefixLen uint8",
222 "\tSrcportOrIcmptypeFirst uint16",
223 "\tSrcportOrIcmptypeLast uint16",
224 "\tDstportOrIcmpcodeFirst uint16",
225 "\tDstportOrIcmpcodeLast uint16",
226 "\tTCPFlagsMask uint8",
227 "\tTCPFlagsValue uint8"}
230 testCtx := new(context)
231 testCtx.packageName = "test-package-name"
233 // prepare input/output output files
234 inputData, err := readFile("testdata/acl.api.json")
235 Expect(err).ShouldNot(HaveOccurred())
236 inFile, err := parseJSON(inputData)
237 Expect(err).ShouldNot(HaveOccurred())
238 Expect(inFile).ToNot(BeNil())
241 types := inFile.Map("types")
242 fields := make([]string, 0)
243 for i := 0; i < types.Len(); i++ {
244 for j := 0; j < types.At(i).Len(); j++ {
245 field := types.At(i).At(j)
246 if field.GetType() == jsongo.TypeArray {
247 err := processMessageField(testCtx, &fields, field, false)
248 Expect(err).ShouldNot(HaveOccurred())
249 Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1]))
255 func TestGenerateMessageFieldMessages(t *testing.T) {
256 // expected results according to acl.api.json in testdata
257 expectedFields := []string{"\tMajor uint32", "\tMinor uint32", "\tRetval int32",
258 "\tVpePid uint32", "\tACLIndex uint32", "\tTag []byte `struc:\"[64]byte\"`",
262 testCtx := new(context)
263 testCtx.packageName = "test-package-name"
265 // prepare input/output output files
266 inputData, err := readFile("testdata/acl.api.json")
267 Expect(err).ShouldNot(HaveOccurred())
268 inFile, err := parseJSON(inputData)
269 Expect(err).ShouldNot(HaveOccurred())
270 Expect(inFile).ToNot(BeNil())
272 // test message fields
273 messages := inFile.Map("messages")
275 fields := make([]string, 0)
276 for i := 0; i < messages.Len(); i++ {
277 for j := 0; j < messages.At(i).Len(); j++ {
278 field := messages.At(i).At(j)
279 if field.GetType() == jsongo.TypeArray {
280 specificFieldName := field.At(1).Get().(string)
281 if specificFieldName == "crc" || specificFieldName == "_vl_msg_id" ||
282 specificFieldName == "client_index" || specificFieldName == "context" {
285 err := processMessageField(testCtx, &fields, field, false)
286 Expect(err).ShouldNot(HaveOccurred())
287 Expect(fields[customIndex]).To(BeEquivalentTo(expectedFields[customIndex]))
289 if customIndex >= len(expectedFields) {
290 // there is too much fields now for one UT...
298 func TestGeneratePackageHeader(t *testing.T) {
301 testCtx := new(context)
302 testCtx.packageName = "test-package-name"
304 // prepare input/output output files
305 inputData, err := readFile("testdata/acl.api.json")
306 Expect(err).ShouldNot(HaveOccurred())
307 inFile, err := parseJSON(inputData)
308 Expect(err).ShouldNot(HaveOccurred())
309 outDir := "test_output_directory"
310 outFile, err := os.Create(outDir)
311 Expect(err).ShouldNot(HaveOccurred())
312 defer os.RemoveAll(outDir)
314 writer := bufio.NewWriter(outFile)
315 Expect(writer.Buffered()).To(BeZero())
316 generateHeader(testCtx, writer, inFile)
317 Expect(writer.Buffered()).ToNot(BeZero())
320 func TestGenerateMessageCommentType(t *testing.T) {
323 testCtx := new(context)
324 testCtx.packageName = "test-package-name"
325 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
327 outDir := "test_output_directory"
328 outFile, err := os.Create(outDir)
329 Expect(err).ShouldNot(HaveOccurred())
330 writer := bufio.NewWriter(outFile)
331 defer os.RemoveAll(outDir)
332 Expect(writer.Buffered()).To(BeZero())
333 generateMessageComment(testCtx, writer, "test-struct", "msg-name", true)
334 Expect(writer.Buffered()).ToNot(BeZero())
337 func TestGenerateMessageCommentMessage(t *testing.T) {
340 testCtx := new(context)
341 testCtx.packageName = "test-package-name"
342 testCtx.inputBuff = bytes.NewBuffer([]byte("test content"))
344 outDir := "test_output_directory"
345 outFile, err := os.Create(outDir)
346 Expect(err).ShouldNot(HaveOccurred())
347 writer := bufio.NewWriter(outFile)
348 defer os.RemoveAll(outDir)
349 Expect(writer.Buffered()).To(BeZero())
350 generateMessageComment(testCtx, writer, "test-struct", "msg-name", false)
351 Expect(writer.Buffered()).ToNot(BeZero())
354 func TestGenerateMessageNameGetter(t *testing.T) {
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 generateMessageNameGetter(writer, "test-struct", "msg-name")
363 Expect(writer.Buffered()).ToNot(BeZero())
366 func TestGenerateTypeNameGetter(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 generateTypeNameGetter(writer, "test-struct", "msg-name")
375 Expect(writer.Buffered()).ToNot(BeZero())
378 func TestGenerateCrcGetter(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 generateCrcGetter(writer, "test-struct", "msg-name")
387 Expect(writer.Buffered()).ToNot(BeZero())
390 func TestTranslateVppType(t *testing.T) {
392 context := new(context)
393 typesToTranslate := []string{"u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f64"}
394 expected := []string{"uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "int64", "float64"}
395 var translated []string
396 for _, value := range typesToTranslate {
397 translated = append(translated, convertToGoType(context, value, false))
399 for index, value := range expected {
400 Expect(value).To(BeEquivalentTo(translated[index]))
405 func TestTranslateVppTypeArray(t *testing.T) {
407 context := new(context)
408 translated := convertToGoType(context, "u8", true)
409 Expect(translated).To(BeEquivalentTo("byte"))
412 func TestTranslateVppUnknownType(t *testing.T) {
414 if recovery := recover(); recovery != nil {
415 t.Logf("Recovered from panic: %v", recovery)
418 context := new(context)
419 convertToGoType(context, "?", false)
422 func TestCamelCase(t *testing.T) {
424 // test camel case functionality
425 expected := "allYourBaseAreBelongToUs"
426 result := camelCaseName("all_your_base_are_belong_to_us")
427 Expect(expected).To(BeEquivalentTo(result))
430 result = camelCaseName(expected)
431 Expect(expected).To(BeEquivalentTo(result))
434 result = camelCaseName(expected)
435 Expect(expected).To(BeEquivalentTo(result))
438 func TestCommonInitialisms(t *testing.T) {
441 for key, value := range commonInitialisms {
442 Expect(value).ShouldNot(BeFalse())
443 Expect(key).ShouldNot(BeEmpty())