github.com/ipld/go-ipld-prime@v0.21.0/schema/dsl/parse_test.go (about)

     1  package schemadsl_test
     2  
     3  import (
     4  	"bytes"
     5  	"flag"
     6  	"os"
     7  	"path/filepath"
     8  	"regexp"
     9  	"strings"
    10  	"testing"
    11  
    12  	ipldjson "github.com/ipld/go-ipld-prime/codec/json"
    13  	"github.com/ipld/go-ipld-prime/node/bindnode"
    14  	"github.com/ipld/go-ipld-prime/schema"
    15  	schemadmt "github.com/ipld/go-ipld-prime/schema/dmt"
    16  	schemadsl "github.com/ipld/go-ipld-prime/schema/dsl"
    17  	"gopkg.in/yaml.v2"
    18  
    19  	qt "github.com/frankban/quicktest"
    20  )
    21  
    22  var update = flag.Bool("update", false, "update testdata files in-place")
    23  
    24  func TestParseSchemaSchema(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	inputSchema := "../../.ipld/specs/schemas/schema-schema.ipldsch"
    28  	inputJSON := "../../.ipld/specs/schemas/schema-schema.ipldsch.json"
    29  
    30  	src, err := os.ReadFile(inputSchema)
    31  	qt.Assert(t, err, qt.IsNil)
    32  
    33  	srcJSON, err := os.ReadFile(inputJSON)
    34  	qt.Assert(t, err, qt.IsNil)
    35  
    36  	testParse(t, string(src), string(srcJSON), func(updated string) {
    37  		err := os.WriteFile(inputJSON, []byte(updated), 0o777)
    38  		qt.Assert(t, err, qt.IsNil)
    39  	})
    40  }
    41  
    42  type yamlFixture struct {
    43  	Schema          string
    44  	Canonical       string `yaml:",omitempty"`
    45  	Expected        string
    46  	ExpectedParsed  interface{}        `yaml:",omitempty"`
    47  	Blocks          []yamlFixtureBlock `yaml:",omitempty"`
    48  	BadBlocks       []string           `yaml:"badBlocks,omitempty"`
    49  	BadBlocksParsed []interface{}      `yaml:",omitempty"`
    50  }
    51  
    52  type yamlFixtureBlock struct {
    53  	Actual         string      `yaml:",omitempty"`
    54  	ActualParsed   interface{} `yaml:",omitempty"`
    55  	Expected       string      `yaml:",omitempty"`
    56  	ExpectedParsed interface{} `yaml:",omitempty"`
    57  }
    58  
    59  func TestParse(t *testing.T) {
    60  	t.Parallel()
    61  
    62  	matches, err := filepath.Glob("../../.ipld/specs/schemas/tests/*.yml")
    63  	qt.Assert(t, err, qt.IsNil)
    64  	qt.Assert(t, matches, qt.Not(qt.HasLen), 0)
    65  
    66  	for _, ymlPath := range matches {
    67  		ymlPath := ymlPath // do not reuse range var
    68  		name := filepath.Base(ymlPath)
    69  
    70  		t.Run(name, func(t *testing.T) {
    71  			t.Parallel()
    72  
    73  			data, err := os.ReadFile(ymlPath)
    74  			qt.Assert(t, err, qt.IsNil)
    75  
    76  			var fixt yamlFixture
    77  			err = yaml.Unmarshal(data, &fixt)
    78  			qt.Assert(t, err, qt.IsNil)
    79  
    80  			testParse(t, fixt.Schema, fixt.Expected, func(updated string) {
    81  				updated = strings.Replace(updated, "\t", "  ", -1)
    82  				fixt.Expected = updated
    83  
    84  				data, err = yaml.Marshal(&fixt)
    85  				qt.Assert(t, err, qt.IsNil)
    86  
    87  				// Note that this will strip comments.
    88  				// Probably don't commit its changes straight away.
    89  				err = os.WriteFile(ymlPath, data, 0777)
    90  				qt.Assert(t, err, qt.IsNil)
    91  			})
    92  		})
    93  	}
    94  }
    95  
    96  func testParse(t *testing.T, inSchema, inJSON string, updateFn func(string)) {
    97  	t.Helper()
    98  
    99  	inJSON = strings.Replace(inJSON, "  ", "\t", -1) // fix non-tab indenting
   100  	crre := regexp.MustCompile(`\r?\n`)
   101  	inJSON = crre.ReplaceAllString(inJSON, "\n") // fix windows carriage-return
   102  
   103  	sch, err := schemadsl.ParseBytes([]byte(inSchema))
   104  	qt.Assert(t, err, qt.IsNil)
   105  
   106  	// Ensure the parsed schema compiles as expected.
   107  	{
   108  		var ts schema.TypeSystem
   109  		ts.Init()
   110  		err := schemadmt.Compile(&ts, sch)
   111  		qt.Assert(t, err, qt.IsNil)
   112  
   113  		qt.Assert(t, ts.Names(), qt.Not(qt.HasLen), 0)
   114  	}
   115  
   116  	// Ensure we can encode the schema as the json codec,
   117  	// and that it results in the same bytes as the ipldsch.json file.
   118  	{
   119  		node := bindnode.Wrap(sch, schemadmt.Prototypes.Schema.Type())
   120  
   121  		var buf bytes.Buffer
   122  		err := ipldjson.Encode(node.Representation(), &buf)
   123  		qt.Assert(t, err, qt.IsNil)
   124  
   125  		// If we're updating, write to the file.
   126  		// Otherwise, expect the files to be equal.
   127  		got := buf.String()
   128  		if *update {
   129  			updateFn(got)
   130  			return
   131  		}
   132  		qt.Assert(t, got, qt.Equals, inJSON,
   133  			qt.Commentf("run 'go test -update' to write to the iplsch.json file"))
   134  	}
   135  
   136  	// TODO: ensure that doing a json codec decode results in the same Schema Go
   137  	// value that we got by parsing the DSL.
   138  }