3e654d7e3c8797abe4757dde564be3e0ad081a9e
[govpp.git] / binapigen / generator_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         "bufio"
19         "fmt"
20         "git.fd.io/govpp.git/binapigen/vppapi"
21         . "github.com/onsi/gomega"
22         "os"
23         "strings"
24         "testing"
25 )
26
27 func TestGoModule(t *testing.T) {
28         const expected = "git.fd.io/govpp.git/binapi"
29
30         impPath, err := resolveImportPath("../binapi")
31         if err != nil {
32                 t.Fatalf("unexpected error: %v", err)
33         }
34         if impPath != expected {
35                 t.Fatalf("expected: %q, got: %q", expected, impPath)
36         }
37 }
38
39 func TestBinapiTypeSizes(t *testing.T) {
40         tests := []struct {
41                 name    string
42                 input   string
43                 expsize int
44         }{
45                 {name: "basic1", input: "u8", expsize: 1},
46                 {name: "basic2", input: "i8", expsize: 1},
47                 {name: "basic3", input: "u16", expsize: 2},
48                 {name: "basic4", input: "i32", expsize: 4},
49                 {name: "string", input: "string", expsize: 1},
50                 {name: "invalid1", input: "x", expsize: 0},
51         }
52         for _, test := range tests {
53                 t.Run(test.name, func(t *testing.T) {
54                         size := getSizeOfBinapiBaseType(test.input, 1)
55                         if size != test.expsize {
56                                 t.Errorf("expected %d, got %d", test.expsize, size)
57                         }
58                 })
59         }
60 }
61
62 func TestBinapiUnionSizes(t *testing.T) {
63         RegisterTestingT(t)
64
65         // order of the union sizes in file generated from union.api.json
66         var sizes = []int{16, 4, 32, 16, 64, 111}
67
68         // remove directory created during test
69         defer func() {
70                 err := os.RemoveAll(testOutputDir)
71                 Expect(err).ToNot(HaveOccurred())
72         }()
73
74         err := GenerateFromFile("vppapi/testdata/union.api.json", Options{OutputDir: testOutputDir})
75         Expect(err).ShouldNot(HaveOccurred())
76
77         file, err := os.Open(testOutputDir + "/union/union.ba.go")
78         Expect(err).ShouldNot(HaveOccurred())
79         defer func() {
80                 err := file.Close()
81                 Expect(err).ToNot(HaveOccurred())
82         }()
83
84         // the generated line with union size is in format XXX_UnionData [<size>]byte
85         // the prefix identifies these lines (the starting tab is important)
86         prefix := fmt.Sprintf("\t%s", "XXX_UnionData [")
87
88         index := 0
89         scanner := bufio.NewScanner(file)
90         for scanner.Scan() {
91                 if strings.HasPrefix(scanner.Text(), prefix) {
92                         Expect(scanner.Text()).To(Equal(prefix + fmt.Sprintf("%d]byte", sizes[index])))
93                         index++
94                 }
95         }
96         // ensure all union sizes were found and tested
97         Expect(index).To(Equal(len(sizes)))
98 }
99
100 // Typed data used for union size evaluation testing.
101 type typeTestData struct {
102         typ    string
103         value  string
104         fields []*typeTestData
105 }
106
107 func (t typeTestData) getUnion(name string) *Union {
108         return &Union{
109                 UnionType: vppapi.UnionType{Name: name},
110                 Fields:    t.getUnionFields(name),
111         }
112 }
113
114 func (t typeTestData) getUnionFields(parentName string) (fields []*Field) {
115         for i, field := range t.fields {
116                 var (
117                         dataType   string
118                         aliasType  *Alias
119                         enumType   *Enum
120                         structType *Struct
121                         unionType  *Union
122                 )
123                 switch field.typ {
124                 case "alias":
125                         aliasType = &Alias{AliasType: vppapi.AliasType{Name: fmt.Sprintf("%s_alias_%d", parentName, i), Type: field.value}}
126                 case "enum":
127                         enumType = &Enum{EnumType: vppapi.EnumType{Name: fmt.Sprintf("%s_enum_%d", parentName, i), Type: field.value}}
128                 case "struct":
129                         structType = &Struct{Fields: field.getUnionFields(fmt.Sprintf("%s_struct_%d", parentName, i))}
130                 case "union":
131                         unionType = field.getUnion(parentName)
132                 default:
133                         dataType = field.value
134                 }
135                 fields = append(fields, &Field{
136                         Field:      vppapi.Field{Name: fmt.Sprintf("%s_field_%d", parentName, i), Type: dataType},
137                         TypeAlias:  aliasType,
138                         TypeEnum:   enumType,
139                         TypeStruct: structType,
140                         TypeUnion:  unionType,
141                 })
142         }
143         return fields
144 }