cuelang.org/go@v0.10.1/encoding/jsonschema/decode_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 jsonschema_test
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"net/url"
    21  	"path"
    22  	"testing"
    23  
    24  	"github.com/go-quicktest/qt"
    25  	"golang.org/x/tools/txtar"
    26  
    27  	"cuelang.org/go/cue"
    28  	"cuelang.org/go/cue/ast"
    29  	"cuelang.org/go/cue/cuecontext"
    30  	"cuelang.org/go/cue/errors"
    31  	"cuelang.org/go/cue/format"
    32  	"cuelang.org/go/cue/token"
    33  	"cuelang.org/go/encoding/json"
    34  	"cuelang.org/go/encoding/jsonschema"
    35  	"cuelang.org/go/encoding/yaml"
    36  	"cuelang.org/go/internal/astinternal"
    37  	"cuelang.org/go/internal/cuetdtest"
    38  	"cuelang.org/go/internal/cuetxtar"
    39  	_ "cuelang.org/go/pkg"
    40  )
    41  
    42  // TestDecode reads the testdata/*.txtar files, converts the contained
    43  // JSON schema to CUE and compares it against the output.
    44  //
    45  // Set CUE_UPDATE=1 to update test files with the corresponding output.
    46  func TestDecode(t *testing.T) {
    47  	test := cuetxtar.TxTarTest{
    48  		Root:   "./testdata",
    49  		Name:   "decode",
    50  		Matrix: cuetdtest.FullMatrix,
    51  	}
    52  	test.Run(t, func(t *cuetxtar.Test) {
    53  		cfg := &jsonschema.Config{}
    54  
    55  		if t.HasTag("openapi") {
    56  			cfg.Root = "#/components/schemas/"
    57  			cfg.Map = func(p token.Pos, a []string) ([]ast.Label, error) {
    58  				// Just for testing: does not validate the path.
    59  				return []ast.Label{ast.NewIdent("#" + a[len(a)-1])}, nil
    60  			}
    61  		}
    62  		cfg.Strict = t.HasTag("strict")
    63  
    64  		ctx := t.Context()
    65  		var v cue.Value
    66  
    67  		for _, f := range t.Archive.Files {
    68  			switch path.Ext(f.Name) {
    69  			case ".json":
    70  				expr, err := json.Extract(f.Name, f.Data)
    71  				if err != nil {
    72  					t.Fatal(err)
    73  				}
    74  				v = ctx.BuildExpr(expr)
    75  			case ".yaml":
    76  				file, err := yaml.Extract(f.Name, f.Data)
    77  				if err != nil {
    78  					t.Fatal(err)
    79  				}
    80  				v = ctx.BuildFile(file)
    81  			}
    82  		}
    83  
    84  		expr, err := jsonschema.Extract(v, cfg)
    85  		if err != nil {
    86  			got := []byte(errors.Details(err, nil))
    87  			got = append(bytes.TrimSpace(got), '\n')
    88  			t.Writer("err").Write(got)
    89  		}
    90  
    91  		if expr != nil {
    92  			b, err := format.Node(expr, format.Simplify())
    93  			if err != nil {
    94  				t.Fatal(errors.Details(err, nil))
    95  			}
    96  
    97  			// verify the generated CUE.
    98  			if !t.HasTag("noverify") {
    99  				v := ctx.CompileBytes(b, cue.Filename("generated.cue"))
   100  				if err := v.Err(); err != nil {
   101  					t.Fatal(errors.Details(err, nil))
   102  				}
   103  			}
   104  
   105  			b = append(bytes.TrimSpace(b), '\n')
   106  			t.Writer("cue").Write(b)
   107  		}
   108  	})
   109  }
   110  
   111  func TestMapURL(t *testing.T) {
   112  	v := cuecontext.New().CompileString(`
   113  type: "object"
   114  properties: x: $ref: "https://something.test/foo#/definitions/blah"
   115  `)
   116  	var calls []string
   117  	expr, err := jsonschema.Extract(v, &jsonschema.Config{
   118  		MapURL: func(u *url.URL) (string, error) {
   119  			calls = append(calls, u.String())
   120  			return "other.test/something:blah", nil
   121  		},
   122  	})
   123  	qt.Assert(t, qt.IsNil(err))
   124  	b, err := format.Node(expr, format.Simplify())
   125  	if err != nil {
   126  		t.Fatal(errors.Details(err, nil))
   127  	}
   128  	qt.Assert(t, qt.DeepEquals(calls, []string{"https://something.test/foo"}))
   129  	qt.Assert(t, qt.Equals(string(b), `
   130  import "other.test/something:blah"
   131  
   132  x?: blah.#blah
   133  ...
   134  `[1:]))
   135  }
   136  
   137  func TestMapURLErrors(t *testing.T) {
   138  	v := cuecontext.New().CompileString(`
   139  type: "object"
   140  properties: {
   141  	x: $ref: "https://something.test/foo#/definitions/x"
   142  	y: $ref: "https://something.test/foo#/definitions/y"
   143  }
   144  `, cue.Filename("foo.cue"))
   145  	_, err := jsonschema.Extract(v, &jsonschema.Config{
   146  		MapURL: func(u *url.URL) (string, error) {
   147  			return "", fmt.Errorf("some error")
   148  		},
   149  	})
   150  	qt.Assert(t, qt.Equals(errors.Details(err, nil), `
   151  cannot determine import path from URL "https://something.test/foo": some error:
   152      foo.cue:4:5
   153  `[1:]))
   154  }
   155  
   156  func TestX(t *testing.T) {
   157  	t.Skip()
   158  	data := `
   159  -- schema.json --
   160  `
   161  
   162  	a := txtar.Parse([]byte(data))
   163  
   164  	ctx := cuecontext.New()
   165  	var v cue.Value
   166  	var err error
   167  	for _, f := range a.Files {
   168  		switch path.Ext(f.Name) {
   169  		case ".json":
   170  			expr, err := json.Extract(f.Name, f.Data)
   171  			if err != nil {
   172  				t.Fatal(err)
   173  			}
   174  			v = ctx.BuildExpr(expr)
   175  		case ".yaml":
   176  			file, err := yaml.Extract(f.Name, f.Data)
   177  			if err != nil {
   178  				t.Fatal(err)
   179  			}
   180  			v = ctx.BuildFile(file)
   181  		}
   182  	}
   183  
   184  	cfg := &jsonschema.Config{ID: "test"}
   185  	expr, err := jsonschema.Extract(v, cfg)
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	t.Fatal(astinternal.DebugStr(expr))
   191  }