...

Source file src/cuelang.org/go/cue/build_test.go

Documentation: cuelang.org/go/cue

     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  }
   264  

View as plain text