cuelang.org/go@v0.13.0/encoding/jsonschema/internal/externaltest/tests.go (about) 1 package externaltest 2 3 import ( 4 "bytes" 5 stdjson "encoding/json" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "cuelang.org/go/cue" 11 "cuelang.org/go/cue/cuecontext" 12 "cuelang.org/go/cue/interpreter/embed" 13 "cuelang.org/go/cue/load" 14 "cuelang.org/go/cue/token" 15 ) 16 17 type Schema struct { 18 location 19 Description string `json:"description"` 20 Comment string `json:"comment,omitempty"` 21 Schema stdjson.RawMessage `json:"schema"` 22 Skip Skip `json:"skip,omitempty"` 23 Tests []*Test `json:"tests"` 24 } 25 26 type Test struct { 27 location 28 Description string `json:"description"` 29 Comment string `json:"comment,omitempty"` 30 Data stdjson.RawMessage `json:"data"` 31 Valid bool `json:"valid"` 32 Skip Skip `json:"skip,omitempty"` 33 } 34 35 // Skip records information about whether a given schema 36 // or test will be skipped when testing. If not present, 37 // the test will be expected to pass. 38 // 39 // Each key in the map represents the name of a point 40 // in the cuetdtest matrix. 41 type Skip map[string]string 42 43 type location struct { 44 root cue.Value 45 path cue.Path 46 } 47 48 func (loc location) Pos() token.Pos { 49 return loc.root.LookupPath(loc.path).Pos() 50 } 51 52 // WriteTestDir writes test data files as read by ReadTestDir 53 // to the given directory. The keys of tests are filenames relative 54 // to dir. 55 func WriteTestDir(dir string, tests map[string][]*Schema) error { 56 for filename, schemas := range tests { 57 filename = filepath.Join(dir, filename) 58 data, err := stdjson.MarshalIndent(schemas, "", "\t") 59 if err != nil { 60 return err 61 } 62 if err != nil { 63 return err 64 } 65 data = append(data, '\n') 66 oldData, err := os.ReadFile(filename) 67 if err != nil { 68 return err 69 } 70 if bytes.Equal(oldData, data) { 71 continue 72 } 73 err = os.WriteFile(filename, data, 0o666) 74 if err != nil { 75 return err 76 } 77 } 78 return nil 79 } 80 81 var ErrNotFound = fmt.Errorf("no external JSON schema tests found") 82 83 // ReadTestDir reads all the external tests from the given directory. 84 func ReadTestDir(dir string) (tests map[string][]*Schema, err error) { 85 if _, err := os.Stat(dir); err != nil { 86 if os.IsNotExist(err) { 87 return nil, ErrNotFound 88 } 89 return nil, err 90 } 91 inst := load.Instances([]string{"."}, &load.Config{ 92 Dir: dir, 93 // Just like in the cue/load tests, prevent Go tests from walking up to the root 94 // directory of the git repository, as that almost always causes test cache misses. 95 ModuleRoot: ".", 96 })[0] 97 if err := inst.Err; err != nil { 98 return nil, err 99 } 100 ctx := cuecontext.New(cuecontext.Interpreter(embed.New())) 101 instVal := ctx.BuildInstance(inst) 102 if err := instVal.Err(); err != nil { 103 return nil, err 104 } 105 val := instVal.LookupPath(cue.MakePath(cue.Str("allTests"))) 106 if err := val.Err(); err != nil { 107 return nil, err 108 } 109 if err := val.Decode(&tests); err != nil { 110 return nil, err 111 } 112 // Fix up the raw JSON data to avoid running into some decode issues. 113 for filename, schemas := range tests { 114 for i, schema := range schemas { 115 schema.location = location{ 116 root: val, 117 path: cue.MakePath(cue.Str(filename), cue.Index(i)), 118 } 119 for j, test := range schema.Tests { 120 test.location = location{ 121 root: val, 122 path: cue.MakePath(cue.Str(filename), cue.Index(i), cue.Str("tests"), cue.Index(j)), 123 } 124 if len(test.Data) == 0 { 125 // See https://github.com/cue-lang/cue/issues/3397 126 test.Data = []byte("null") 127 continue 128 } 129 // See https://github.com/cue-lang/cue/issues/3398 130 test.Data = bytes.ReplaceAll(test.Data, []byte("\ufeff"), []byte(`\ufeff`)) 131 } 132 } 133 } 134 return tests, nil 135 }