cuelang.org/go@v0.10.1/internal/filetypes/filetypes_test.go (about)

     1  // Copyright 2020 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 filetypes
    16  
    17  import (
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/google/go-cmp/cmp/cmpopts"
    23  
    24  	"cuelang.org/go/cue/build"
    25  	"cuelang.org/go/cue/errors"
    26  )
    27  
    28  func check(t *testing.T, want, x interface{}, err error) {
    29  	t.Helper()
    30  	if err != nil {
    31  		x = errors.String(err.(errors.Error))
    32  	}
    33  	if diff := cmp.Diff(want, x, cmpopts.EquateEmpty()); diff != "" {
    34  		t.Errorf("unexpected result; -want +got\n%s", diff)
    35  	}
    36  }
    37  
    38  func TestFromFile(t *testing.T) {
    39  	testCases := []struct {
    40  		name string
    41  		in   build.File
    42  		mode Mode
    43  		out  interface{}
    44  	}{{
    45  		name: "must specify encoding",
    46  		in:   build.File{},
    47  		out:  `modes.input.FileInfo: field not found: encoding`,
    48  	}, {
    49  		// Default without any
    50  		name: "cue",
    51  		in: build.File{
    52  			Filename: "",
    53  			Encoding: build.CUE,
    54  		},
    55  		mode: Def,
    56  		out: &FileInfo{
    57  			File: &build.File{
    58  				Filename: "",
    59  				Encoding: "cue",
    60  				Form:     "schema",
    61  			},
    62  			Definitions:  true,
    63  			Data:         true,
    64  			Optional:     true,
    65  			Constraints:  true,
    66  			References:   true,
    67  			Cycles:       true,
    68  			KeepDefaults: true,
    69  			Incomplete:   true,
    70  			Imports:      true,
    71  			Docs:         true,
    72  			Attributes:   true,
    73  		},
    74  	}, {
    75  		// CUE encoding in data form.
    76  		name: "data: cue",
    77  		in: build.File{
    78  			Filename: "",
    79  			Form:     build.Data,
    80  			Encoding: build.CUE,
    81  		},
    82  		mode: Input,
    83  		out: &FileInfo{
    84  			File: &build.File{
    85  				Filename: "",
    86  				Encoding: "cue",
    87  				Form:     "data",
    88  			},
    89  			Data:       true,
    90  			Docs:       true,
    91  			Attributes: true,
    92  		},
    93  	}, {
    94  		// Filename starting with a . but no other extension.
    95  		name: "filename-with-dot",
    96  		in: build.File{
    97  			Filename: ".json",
    98  		},
    99  		mode: Def,
   100  		out:  `modes.def.FileInfo: field not found: encoding`,
   101  	}, {
   102  		name: "yaml",
   103  		mode: Def,
   104  		in: build.File{
   105  			Filename: "foo.yaml",
   106  		},
   107  		out: &FileInfo{
   108  			File: &build.File{
   109  				Filename: "foo.yaml",
   110  				Encoding: "yaml",
   111  				Form:     "graph",
   112  			},
   113  			Data:       true,
   114  			References: true,
   115  			Cycles:     true,
   116  			Stream:     true,
   117  			Docs:       true,
   118  			Attributes: true,
   119  		},
   120  	}, {
   121  		name: "yaml+openapi",
   122  		in: build.File{
   123  			Filename:       "foo.yaml",
   124  			Interpretation: "openapi",
   125  		},
   126  		out: &FileInfo{
   127  			File: &build.File{
   128  				Filename:       "foo.yaml",
   129  				Encoding:       "yaml",
   130  				Interpretation: "openapi",
   131  				Form:           "schema",
   132  			},
   133  			Definitions:  true,
   134  			Data:         true,
   135  			Optional:     true,
   136  			Constraints:  true,
   137  			References:   true,
   138  			Cycles:       true,
   139  			KeepDefaults: true,
   140  			Incomplete:   true,
   141  			Imports:      true,
   142  			Docs:         true,
   143  			Attributes:   true,
   144  		},
   145  	}, {
   146  		name: "JSONDefault",
   147  		mode: Input,
   148  		in: build.File{
   149  			Filename: "data.json",
   150  		},
   151  		out: &FileInfo{
   152  			File: &build.File{
   153  				Filename:       "data.json",
   154  				Encoding:       "json",
   155  				Interpretation: "auto",
   156  				Form:           "schema",
   157  			},
   158  			Definitions:  true,
   159  			Data:         true,
   160  			Optional:     true,
   161  			Constraints:  true,
   162  			References:   true,
   163  			Cycles:       true,
   164  			KeepDefaults: true,
   165  			Incomplete:   true,
   166  			Imports:      true,
   167  			Docs:         true,
   168  			Attributes:   true,
   169  		},
   170  	}, {
   171  		name: "JSONSchema",
   172  		in: build.File{
   173  			Filename:       "foo.json",
   174  			Interpretation: "jsonschema",
   175  		},
   176  		out: &FileInfo{
   177  			File: &build.File{
   178  				Filename:       "foo.json",
   179  				Encoding:       "json",
   180  				Interpretation: "jsonschema",
   181  				Form:           "schema",
   182  			},
   183  			Definitions:  true,
   184  			Data:         true,
   185  			Optional:     true,
   186  			Constraints:  true,
   187  			References:   true,
   188  			Cycles:       true,
   189  			KeepDefaults: true,
   190  			Incomplete:   true,
   191  			Imports:      true,
   192  			Docs:         true,
   193  			Attributes:   true,
   194  		},
   195  	}, {
   196  		name: "JSONOpenAPI",
   197  		in: build.File{
   198  			Filename:       "foo.json",
   199  			Interpretation: "openapi",
   200  		},
   201  		mode: Def,
   202  		out: &FileInfo{
   203  			File: &build.File{
   204  				Filename:       "foo.json",
   205  				Encoding:       "json",
   206  				Interpretation: "openapi",
   207  				Form:           "schema",
   208  			},
   209  			Definitions:  true,
   210  			Data:         true,
   211  			Optional:     true,
   212  			Constraints:  true,
   213  			References:   true,
   214  			Cycles:       true,
   215  			KeepDefaults: true,
   216  			Incomplete:   true,
   217  			Imports:      true,
   218  			Docs:         true,
   219  			Attributes:   true,
   220  		},
   221  	}, {
   222  		name: "OpenAPIDefaults",
   223  		in: build.File{
   224  			Filename:       "-",
   225  			Interpretation: "openapi",
   226  		},
   227  		mode: Def,
   228  		out: &FileInfo{
   229  			File: &build.File{
   230  				Filename:       "-",
   231  				Encoding:       "json",
   232  				Interpretation: "openapi",
   233  				Form:           "schema",
   234  			},
   235  			Definitions:  true,
   236  			Data:         true,
   237  			Optional:     true,
   238  			Constraints:  true,
   239  			References:   true,
   240  			Cycles:       true,
   241  			KeepDefaults: true,
   242  			Incomplete:   true,
   243  			Imports:      true,
   244  			Docs:         true,
   245  			Attributes:   true,
   246  		},
   247  	}, {
   248  		name: "Go",
   249  		in: build.File{
   250  			Filename: "foo.go",
   251  		},
   252  		mode: Def,
   253  		out: &FileInfo{
   254  			File: &build.File{
   255  				Filename: "foo.go",
   256  				Encoding: "code",
   257  				Form:     "schema",
   258  				Tags:     map[string]string{"lang": "go"},
   259  			},
   260  			Definitions:  true,
   261  			Data:         true,
   262  			Optional:     true,
   263  			Constraints:  true,
   264  			References:   true,
   265  			Cycles:       true,
   266  			KeepDefaults: true,
   267  			Incomplete:   true,
   268  			Imports:      true,
   269  			Stream:       false,
   270  			Docs:         true,
   271  			Attributes:   true,
   272  		},
   273  	}}
   274  	for _, tc := range testCases {
   275  		t.Run(tc.name, func(t *testing.T) {
   276  			info, err := FromFile(&tc.in, tc.mode)
   277  			check(t, tc.out, info, err)
   278  		})
   279  	}
   280  }
   281  
   282  func TestParseFile(t *testing.T) {
   283  	// TODO(errors): wrong path?
   284  	testCases := []struct {
   285  		in   string
   286  		mode Mode
   287  		out  interface{}
   288  	}{{
   289  		in:   "file.json",
   290  		mode: Input,
   291  		out: &build.File{
   292  			Filename:       "file.json",
   293  			Encoding:       "json",
   294  			Interpretation: "auto",
   295  		},
   296  	}, {
   297  		in:   ".json",
   298  		mode: Input,
   299  		out:  `no encoding specified for file ".json"`,
   300  	}, {
   301  		in:   ".json.yaml",
   302  		mode: Input,
   303  		out: &build.File{
   304  			Filename:       ".json.yaml",
   305  			Encoding:       "yaml",
   306  			Interpretation: "auto",
   307  		},
   308  	}, {
   309  		in:   "file.json",
   310  		mode: Def,
   311  		out: &build.File{
   312  			Filename: "file.json",
   313  			Encoding: "json",
   314  		},
   315  	}, {
   316  		in: "schema:file.json",
   317  		out: &build.File{
   318  			Filename:       "file.json",
   319  			Encoding:       "json",
   320  			Interpretation: "auto",
   321  			Form:           "schema",
   322  		},
   323  	}, {
   324  		in: "openapi:-",
   325  		out: &build.File{
   326  			Filename:       "-",
   327  			Encoding:       "json",
   328  			Interpretation: "openapi",
   329  		},
   330  	}, {
   331  		in: "cue:file.json",
   332  		out: &build.File{
   333  			Filename: "file.json",
   334  			Encoding: "cue",
   335  		},
   336  	}, {
   337  		in: "cue+schema:-",
   338  		out: &build.File{
   339  			Filename: "-",
   340  			Encoding: "cue",
   341  			Form:     "schema",
   342  		},
   343  	}, {
   344  		in: "code+lang=js:foo.x",
   345  		out: &build.File{
   346  			Filename: "foo.x",
   347  			Encoding: "code",
   348  			Tags:     map[string]string{"lang": "js"},
   349  		},
   350  	}, {
   351  		in:  "foo:file.bar",
   352  		out: `unknown filetype foo`,
   353  	}, {
   354  		in:  "file.bar",
   355  		out: `unknown file extension .bar`,
   356  	}, {
   357  		in:   "-",
   358  		mode: Input,
   359  		out: &build.File{
   360  			Filename: "-",
   361  			Encoding: "cue",
   362  		},
   363  	}, {
   364  		in:   "-",
   365  		mode: Export,
   366  		out: &build.File{
   367  			Filename: "-",
   368  			Encoding: "json",
   369  		},
   370  	}}
   371  	for _, tc := range testCases {
   372  		t.Run(tc.in, func(t *testing.T) {
   373  			f, err := ParseFile(tc.in, tc.mode)
   374  			check(t, tc.out, f, err)
   375  		})
   376  	}
   377  }
   378  
   379  func TestParseArgs(t *testing.T) {
   380  	testCases := []struct {
   381  		in  string
   382  		out interface{}
   383  	}{{
   384  		in: "foo.json baz.yaml",
   385  		out: []*build.File{
   386  			{
   387  				Filename:       "foo.json",
   388  				Encoding:       "json",
   389  				Interpretation: "auto",
   390  			},
   391  			{
   392  				Filename:       "baz.yaml",
   393  				Encoding:       "yaml",
   394  				Interpretation: "auto",
   395  			},
   396  		},
   397  	}, {
   398  		in: "data: foo.cue",
   399  		out: []*build.File{
   400  			{Filename: "foo.cue", Encoding: "cue", Form: "data"},
   401  		},
   402  	}, {
   403  		in: "json: foo.json bar.data jsonschema: bar.schema",
   404  		out: []*build.File{
   405  			{Filename: "foo.json", Encoding: "json"}, // no auto!
   406  			{Filename: "bar.data", Encoding: "json"},
   407  			{
   408  				Filename:       "bar.schema",
   409  				Encoding:       "json",
   410  				Interpretation: "jsonschema",
   411  			},
   412  		},
   413  	}, {
   414  		in: `json: c:\foo.json c:\path\to\file.dat`,
   415  		out: []*build.File{
   416  			{Filename: `c:\foo.json`, Encoding: "json"},
   417  			{Filename: `c:\path\to\file.dat`, Encoding: "json"},
   418  		},
   419  	}, {
   420  		in:  "json: json+schema: bar.schema",
   421  		out: `scoped qualifier "json:" without file`,
   422  	}, {
   423  		in:  "json:",
   424  		out: `scoped qualifier "json:" without file`,
   425  	}, {
   426  		in:  "json:foo:bar.yaml",
   427  		out: `unsupported file name "json:foo:bar.yaml": may not have ':'`,
   428  	}}
   429  	for _, tc := range testCases {
   430  		t.Run(tc.in, func(t *testing.T) {
   431  			files, err := ParseArgs(strings.Split(tc.in, " "))
   432  			check(t, tc.out, files, err)
   433  		})
   434  	}
   435  }