github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/encoding/openapi/openapi_test.go (about) 1 // Copyright 2019 CUE Authors 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 openapi_test 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "io/ioutil" 21 "path/filepath" 22 "strings" 23 "testing" 24 25 "github.com/kylelemons/godebug/diff" 26 27 "github.com/joomcode/cue/cue" 28 "github.com/joomcode/cue/cue/ast" 29 "github.com/joomcode/cue/cue/errors" 30 "github.com/joomcode/cue/cue/load" 31 "github.com/joomcode/cue/encoding/openapi" 32 "github.com/joomcode/cue/internal/cuetest" 33 ) 34 35 func TestParseDefinitions(t *testing.T) { 36 info := *(*openapi.OrderedMap)(ast.NewStruct( 37 "title", ast.NewString("test"), 38 "version", ast.NewString("v1"), 39 )) 40 defaultConfig := &openapi.Config{} 41 resolveRefs := &openapi.Config{Info: info, ExpandReferences: true} 42 43 testCases := []struct { 44 in, out string 45 config *openapi.Config 46 err string 47 }{{ 48 in: "structural.cue", 49 out: "structural.json", 50 config: resolveRefs, 51 }, { 52 in: "nested.cue", 53 out: "nested.json", 54 config: defaultConfig, 55 }, { 56 in: "simple.cue", 57 out: "simple.json", 58 config: resolveRefs, 59 }, { 60 in: "simple.cue", 61 out: "simple-filter.json", 62 config: &openapi.Config{Info: info, FieldFilter: "min.*|max.*"}, 63 }, { 64 in: "array.cue", 65 out: "array.json", 66 config: defaultConfig, 67 }, { 68 in: "enum.cue", 69 out: "enum.json", 70 config: defaultConfig, 71 }, { 72 in: "struct.cue", 73 out: "struct.json", 74 config: defaultConfig, 75 }, { 76 in: "strings.cue", 77 out: "strings.json", 78 config: defaultConfig, 79 }, { 80 in: "nums.cue", 81 out: "nums.json", 82 config: defaultConfig, 83 }, { 84 in: "nums.cue", 85 out: "nums-v3.1.0.json", 86 config: &openapi.Config{Info: info, Version: "3.1.0"}, 87 }, { 88 in: "builtins.cue", 89 out: "builtins.json", 90 config: defaultConfig, 91 }, { 92 in: "oneof.cue", 93 out: "oneof.json", 94 config: defaultConfig, 95 }, { 96 in: "oneof.cue", 97 out: "oneof-resolve.json", 98 config: resolveRefs, 99 }, { 100 in: "openapi.cue", 101 out: "openapi.json", 102 config: defaultConfig, 103 }, { 104 in: "openapi.cue", 105 out: "openapi-norefs.json", 106 config: resolveRefs, 107 }, { 108 in: "embed.cue", 109 out: "embed.json", 110 config: defaultConfig, 111 }, { 112 in: "embed.cue", 113 out: "embed-norefs.json", 114 config: resolveRefs, 115 }, { 116 in: "oneof.cue", 117 out: "oneof-funcs.json", 118 config: &openapi.Config{ 119 Info: info, 120 ReferenceFunc: func(inst *cue.Instance, path []string) string { 121 return strings.ToUpper(strings.Join(path, "_")) 122 }, 123 DescriptionFunc: func(v cue.Value) string { 124 return "Randomly picked description from a set of size one." 125 }, 126 }, 127 }, { 128 in: "refs.cue", 129 out: "refs.json", 130 config: &openapi.Config{ 131 Info: info, 132 ReferenceFunc: func(inst *cue.Instance, path []string) string { 133 switch { 134 case strings.HasPrefix(path[0], "Excluded"): 135 return "" 136 } 137 return strings.Join(path, ".") 138 }, 139 }, 140 }, { 141 in: "issue131.cue", 142 out: "issue131.json", 143 config: &openapi.Config{Info: info, SelfContained: true}, 144 }, { 145 // Issue #915 146 in: "cycle.cue", 147 out: "cycle.json", 148 config: &openapi.Config{Info: info}, 149 }, { 150 // Issue #915 151 in: "cycle.cue", 152 config: &openapi.Config{Info: info, ExpandReferences: true}, 153 err: "cycle", 154 }} 155 for _, tc := range testCases { 156 t.Run(tc.out, func(t *testing.T) { 157 filename := filepath.FromSlash(tc.in) 158 159 inst := cue.Build(load.Instances([]string{filename}, &load.Config{ 160 Dir: "./testdata", 161 }))[0] 162 if inst.Err != nil { 163 t.Fatal(errors.Details(inst.Err, nil)) 164 } 165 166 b, err := openapi.Gen(inst, tc.config) 167 if err != nil { 168 if tc.err == "" { 169 t.Fatal("unexpected error:", errors.Details(inst.Err, nil)) 170 } 171 return 172 } 173 174 if tc.err != "" { 175 t.Fatal("unexpected success:", tc.err) 176 } else { 177 all, err := tc.config.All(inst) 178 if err != nil { 179 t.Fatal(err) 180 } 181 walk(all) 182 } 183 184 var out = &bytes.Buffer{} 185 _ = json.Indent(out, b, "", " ") 186 187 wantFile := filepath.Join("testdata", tc.out) 188 if cuetest.UpdateGoldenFiles { 189 _ = ioutil.WriteFile(wantFile, out.Bytes(), 0644) 190 return 191 } 192 193 b, err = ioutil.ReadFile(wantFile) 194 if err != nil { 195 t.Fatal(err) 196 } 197 198 if d := diff.Diff(string(b), out.String()); d != "" { 199 t.Errorf("files differ:\n%v", d) 200 } 201 }) 202 } 203 } 204 205 // walk traverses an openapi.OrderedMap. This is a helper function 206 // used to ensure that a generated OpenAPI value is well-formed. 207 func walk(om *openapi.OrderedMap) { 208 for _, p := range om.Pairs() { 209 switch p := p.Value.(type) { 210 case *openapi.OrderedMap: 211 walk(p) 212 case []*openapi.OrderedMap: 213 for _, om := range p { 214 walk(om) 215 } 216 } 217 } 218 } 219 220 // TODO: move OpenAPI testing to txtar and allow errors. 221 func TestIssue1234(t *testing.T) { 222 var r cue.Runtime 223 inst, err := r.Compile("test", ` 224 #Test: or([]) 225 226 `) 227 if err != nil { 228 t.Fatal(err) 229 } 230 231 _, err = openapi.Gen(inst, &openapi.Config{}) 232 if err == nil { 233 t.Fatal("expected error") 234 } 235 } 236 237 // This is for debugging purposes. Do not remove. 238 func TestX(t *testing.T) { 239 t.Skip() 240 241 var r cue.Runtime 242 inst, err := r.Compile("test", ` 243 `) 244 if err != nil { 245 t.Fatal(err) 246 } 247 248 b, err := openapi.Gen(inst, &openapi.Config{ 249 // ExpandReferences: true, 250 }) 251 if err != nil { 252 t.Fatal(errors.Details(err, nil)) 253 } 254 255 var out = &bytes.Buffer{} 256 _ = json.Indent(out, b, "", " ") 257 t.Error(out.String()) 258 }