cuelang.org/go@v0.10.1/cue/build_test.go (about) 1 // Copyright 2018 The 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 cue_test 16 17 import ( 18 "fmt" 19 "testing" 20 21 "cuelang.org/go/cue" 22 "cuelang.org/go/cue/ast" 23 "cuelang.org/go/cue/build" 24 "cuelang.org/go/cue/cuecontext" 25 "cuelang.org/go/cue/token" 26 "cuelang.org/go/internal/core/debug" 27 "cuelang.org/go/internal/value" 28 ) 29 30 func TestFromExpr(t *testing.T) { 31 testCases := []struct { 32 expr ast.Expr 33 out string 34 }{{ 35 expr: ast.NewString("Hello"), 36 out: `"Hello"`, 37 }, { 38 expr: ast.NewList( 39 ast.NewString("Hello"), 40 ast.NewString("World"), 41 ), 42 out: `["Hello", "World"]`, 43 }} 44 for _, tc := range testCases { 45 t.Run("", func(t *testing.T) { 46 r := cuecontext.New() 47 v := r.BuildExpr(tc.expr) 48 if err := v.Err(); err != nil { 49 t.Fatal(err) 50 } 51 if got := fmt.Sprint(v); got != tc.out { 52 t.Errorf("\n got: %v; want %v", got, tc.out) 53 } 54 }) 55 } 56 } 57 58 func TestBuild(t *testing.T) { 59 files := func(s ...string) []string { return s } 60 insts := func(i ...*bimport) []*bimport { return i } 61 pkg1 := &bimport{ 62 "pkg1", 63 files(` 64 package pkg1 65 66 Object: "World" 67 `), 68 } 69 pkg2 := &bimport{ 70 "mod.test/foo/pkg2:pkg", 71 files(` 72 package pkg 73 74 Number: 12 75 `), 76 } 77 pkg3 := &bimport{ 78 "mod.test/foo/v1:pkg3", 79 files(` 80 package pkg3 81 82 List: [1,2,3] 83 `), 84 } 85 86 testCases := []struct { 87 instances []*bimport 88 emit string 89 }{{ 90 insts(&bimport{"", files(`test: "ok"`)}), 91 `{test:"ok"}`, 92 }, { 93 insts(&bimport{"", 94 files( 95 `package test 96 97 import "math" 98 99 "Pi: \(math.Pi)!"`)}), 100 `"Pi: 3.14159265358979323846264338327950288419716939937510582097494459!"`, 101 }, { 102 insts(&bimport{"", 103 files( 104 `package test 105 106 import math2 "math" 107 108 "Pi: \(math2.Pi)!"`)}), 109 `"Pi: 3.14159265358979323846264338327950288419716939937510582097494459!"`, 110 }, { 111 insts(pkg1, &bimport{"", 112 files( 113 `package test 114 115 import "pkg1" 116 117 "Hello \(pkg1.Object)!"`), 118 }), 119 `"Hello World!"`, 120 }, { 121 insts(pkg1, &bimport{"", 122 files( 123 `package test 124 125 import "pkg1" 126 127 "Hello \(pkg1.Object)!"`), 128 }), 129 `"Hello World!"`, 130 }, { 131 insts(pkg1, &bimport{"", 132 files( 133 `package test 134 135 import pkg2 "pkg1" 136 #pkg1: pkg2.Object 137 138 "Hello \(#pkg1)!"`), 139 }), 140 `"Hello World!"`, 141 }, { 142 insts(pkg1, pkg2, &bimport{"", 143 files( 144 `package test 145 146 import bar "pkg1" 147 import baz "mod.test/foo/pkg2:pkg" 148 149 pkg1: Object: 3 150 "Hello \(pkg1.Object)!"`), 151 }), 152 `imported and not used: "pkg1" as bar (and 1 more errors)`, 153 }, { 154 insts(pkg2, &bimport{"", 155 files( 156 `package test 157 158 import "mod.test/foo/pkg2:pkg" 159 160 "Hello \(pkg2.Number)!"`), 161 }), 162 `imported and not used: "mod.test/foo/pkg2:pkg" (and 1 more errors)`, 163 // `file0.cue:5:14: unresolved reference pkg2`, 164 }, { 165 insts(pkg2, &bimport{"", 166 files( 167 `package test 168 169 import "mod.test/foo/pkg2:pkg" 170 171 "Hello \(pkg.Number)!"`), 172 }), 173 `"Hello 12!"`, 174 }, { 175 insts(pkg3, &bimport{"", 176 files( 177 `package test 178 179 import "mod.test/foo/v1:pkg3" 180 181 "Hello \(pkg3.List[1])!"`), 182 }), 183 `"Hello 2!"`, 184 }, { 185 insts(pkg3, &bimport{"", 186 files( 187 `package test 188 189 import "mod.test/foo/v1:pkg3" 190 191 pkg3: 3 192 193 "Hello \(pkg3.List[1])!"`), 194 }), 195 `pkg3 redeclared as imported package name 196 previous declaration at file0.cue:5:5`, 197 }} 198 for _, tc := range testCases { 199 t.Run("", func(t *testing.T) { 200 insts := cue.Build(makeInstances(tc.instances)) 201 var got string 202 if err := insts[0].Err; err != nil { 203 got = err.Error() 204 } else { 205 cfg := &debug.Config{Compact: true} 206 r, v := value.ToInternal(insts[0].Value()) 207 got = debug.NodeString(r, v, cfg) 208 } 209 if got != tc.emit { 210 t.Errorf("\n got: %s\nwant: %s", got, tc.emit) 211 } 212 }) 213 } 214 } 215 216 type builder struct { 217 ctxt *build.Context 218 imports map[string]*bimport 219 } 220 221 func (b *builder) load(pos token.Pos, path string) *build.Instance { 222 bi := b.imports[path] 223 if bi == nil { 224 return nil 225 } 226 return b.build(bi) 227 } 228 229 type bimport struct { 230 path string // "" means top-level 231 files []string 232 } 233 234 func makeInstances(insts []*bimport) (instances []*build.Instance) { 235 b := builder{ 236 ctxt: build.NewContext(), 237 imports: map[string]*bimport{}, 238 } 239 for _, bi := range insts { 240 if bi.path != "" { 241 b.imports[bi.path] = bi 242 } 243 } 244 for _, bi := range insts { 245 if bi.path == "" { 246 instances = append(instances, b.build(bi)) 247 } 248 } 249 return 250 } 251 252 func (b *builder) build(bi *bimport) *build.Instance { 253 path := bi.path 254 if path == "" { 255 path = "dir" 256 } 257 p := b.ctxt.NewInstance(path, b.load) 258 for i, f := range bi.files { 259 _ = p.AddFile(fmt.Sprintf("file%d.cue", i), f) 260 } 261 _ = p.Complete() 262 return p 263 }