| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package parse_test |
| |
| import ( |
| "math/big" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "v.io/x/ref/lib/vdl/internal/vdltestutil" |
| "v.io/x/ref/lib/vdl/parse" |
| "v.io/x/ref/lib/vdl/vdlutil" |
| ) |
| |
| func pos(line, col int) parse.Pos { |
| return parse.Pos{line, col} |
| } |
| |
| func sp(str string, line, col int) parse.StringPos { |
| return parse.StringPos{String: str, Pos: pos(line, col)} |
| } |
| |
| func lf(l, f parse.StringPos) parse.LangFmt { |
| return parse.LangFmt{Lang: l, Fmt: f} |
| } |
| |
| func np(name string, line, col int) parse.NamePos { |
| return parse.NamePos{Name: name, Pos: pos(line, col)} |
| } |
| |
| func npptr(name string, line, col int) *parse.NamePos { |
| ret := np(name, line, col) |
| return &ret |
| } |
| |
| func tn(name string, line, col int) *parse.TypeNamed { |
| return &parse.TypeNamed{Name: name, P: pos(line, col)} |
| } |
| |
| func cn(name string, line, col int) *parse.ConstNamed { |
| return &parse.ConstNamed{Name: name, P: pos(line, col)} |
| } |
| |
| func cl(lit interface{}, line, col int) *parse.ConstLit { |
| return &parse.ConstLit{Lit: lit, P: pos(line, col)} |
| } |
| |
| // Tests of vdl imports and file parsing. |
| type vdlParseTest struct { |
| name string |
| src string |
| expect *parse.File |
| errors []string |
| } |
| |
| func testParseVDL(t *testing.T, test vdlParseTest, opts parse.Opts) { |
| errs := vdlutil.NewErrors(-1) |
| actual := parse.ParseFile("testfile", strings.NewReader(test.src), opts, errs) |
| vdltestutil.ExpectResult(t, errs, test.name, test.errors...) |
| if !reflect.DeepEqual(test.expect, actual) { |
| t.Errorf("%v\nEXPECT %+v\nACTUAL %+v", test.name, test.expect, actual) |
| } |
| } |
| |
| func TestParseVDLImports(t *testing.T) { |
| for _, test := range vdlImportsTests { |
| testParseVDL(t, test, parse.Opts{ImportsOnly: true}) |
| } |
| for _, test := range vdlFileTests { |
| // We only run the success tests from vdlFileTests on the imports only |
| // parser, since the failure tests are testing failures in stuff after the |
| // imports, which won't cause failures in the imports only parser. |
| // |
| // The imports-only parser isn't supposed to fill in fields after the |
| // imports, so we clear them from the expected result. We must copy the |
| // file to ensure the actual vdlFileTests isn't overwritten since the |
| // full-parser tests needs the full expectations. The test itself doesn't |
| // need to be copied, since it's already copied in the range-for. |
| if test.expect != nil { |
| copyFile := *test.expect |
| test.expect = ©File |
| test.expect.TypeDefs = nil |
| test.expect.ConstDefs = nil |
| test.expect.ErrorDefs = nil |
| test.expect.Interfaces = nil |
| testParseVDL(t, test, parse.Opts{ImportsOnly: true}) |
| } |
| } |
| } |
| |
| func TestParseVDLFile(t *testing.T) { |
| for _, test := range append(vdlImportsTests, vdlFileTests...) { |
| testParseVDL(t, test, parse.Opts{ImportsOnly: false}) |
| } |
| } |
| |
| // Tests of config imports and file parsing. |
| type configTest struct { |
| name string |
| src string |
| expect *parse.Config |
| errors []string |
| } |
| |
| func testParseConfig(t *testing.T, test configTest, opts parse.Opts) { |
| errs := vdlutil.NewErrors(-1) |
| actual := parse.ParseConfig("testfile", strings.NewReader(test.src), opts, errs) |
| vdltestutil.ExpectResult(t, errs, test.name, test.errors...) |
| if !reflect.DeepEqual(test.expect, actual) { |
| t.Errorf("%v\nEXPECT %+v\nACTUAL %+v", test.name, test.expect, actual) |
| } |
| } |
| |
| func TestParseConfigImports(t *testing.T) { |
| for _, test := range configTests { |
| // We only run the success tests from configTests on the imports only |
| // parser, since the failure tests are testing failures in stuff after the |
| // imports, which won't cause failures in the imports only parser. |
| // |
| // The imports-only parser isn't supposed to fill in fields after the |
| // imports, so we clear them from the expected result. We must copy the |
| // file to ensure the actual configTests isn't overwritten since the |
| // full-parser tests needs the full expectations. The test itself doesn't |
| // need to be copied, since it's already copied in the range-for. |
| if test.expect != nil { |
| copyConfig := *test.expect |
| test.expect = ©Config |
| test.expect.Config = nil |
| test.expect.ConstDefs = nil |
| testParseConfig(t, test, parse.Opts{ImportsOnly: true}) |
| } |
| } |
| } |
| |
| func TestParseConfig(t *testing.T) { |
| for _, test := range configTests { |
| testParseConfig(t, test, parse.Opts{ImportsOnly: false}) |
| } |
| } |
| |
| // vdlImportsTests contains tests of stuff up to and including the imports. |
| var vdlImportsTests = []vdlParseTest{ |
| // Empty file isn't allowed (need at least a package clause). |
| { |
| "FAILEmptyFile", |
| "", |
| nil, |
| []string{"vdl file must start with package clause"}}, |
| |
| // Comment tests. |
| { |
| "PackageDocOneLiner", |
| `// One liner |
| // Another line |
| package testpkg`, |
| &parse.File{BaseName: "testfile", PackageDef: parse.NamePos{Name: "testpkg", Pos: pos(3, 9), Doc: `// One liner |
| // Another line |
| `}}, |
| nil}, |
| { |
| "PackageDocMultiLiner", |
| `/* Multi liner |
| Another line |
| */ |
| package testpkg`, |
| &parse.File{BaseName: "testfile", PackageDef: parse.NamePos{Name: "testpkg", Pos: pos(4, 9), Doc: `/* Multi liner |
| Another line |
| */ |
| `}}, |
| nil}, |
| { |
| "FileDocNoPackageDoc", |
| `// File doc, has extra newline so not package doc |
| |
| package testpkg`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 3, 9), Doc: "// File doc, has extra newline so not package doc\n"}, |
| nil}, |
| { |
| "FileDocAndPackageDoc", |
| `// File doc |
| |
| // Package doc |
| package testpkg`, |
| &parse.File{BaseName: "testfile", PackageDef: parse.NamePos{Name: "testpkg", Pos: pos(4, 9), Doc: "// Package doc\n"}, Doc: "// File doc\n"}, |
| nil}, |
| { |
| "FAILUnterminatedComment", |
| `/* Unterminated |
| Another line |
| package testpkg`, |
| nil, |
| []string{"comment not terminated"}}, |
| |
| // Package tests. |
| { |
| "Package", |
| "package testpkg;", |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9)}, |
| nil}, |
| { |
| "PackageNoSemi", |
| "package testpkg", |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9)}, |
| nil}, |
| { |
| "FAILBadPackageName", |
| "package foo.bar", |
| nil, |
| []string{"testfile:1:12 syntax error"}}, |
| |
| // Import tests. |
| { |
| "EmptyImport", |
| `package testpkg; |
| import ( |
| )`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9)}, |
| nil}, |
| { |
| "OneImport", |
| `package testpkg; |
| import "foo/bar";`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 2, 8)}}}, |
| nil}, |
| { |
| "OneImportLocalNameNoSemi", |
| `package testpkg |
| import baz "foo/bar"`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("baz", 2, 8)}}}, |
| nil}, |
| { |
| "OneImportParens", |
| `package testpkg |
| import ( |
| "foo/bar"; |
| )`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 3, 3)}}}, |
| nil}, |
| { |
| "OneImportParensNoSemi", |
| `package testpkg |
| import ( |
| "foo/bar" |
| )`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 3, 3)}}}, |
| nil}, |
| { |
| "MixedImports", |
| `package testpkg |
| import "foo/bar" |
| import ( |
| "baz";"a/b" |
| "c/d" |
| ) |
| import "z"`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Imports: []*parse.Import{ |
| {Path: "foo/bar", NamePos: np("", 2, 8)}, |
| {Path: "baz", NamePos: np("", 4, 3)}, |
| {Path: "a/b", NamePos: np("", 4, 9)}, |
| {Path: "c/d", NamePos: np("", 5, 3)}, |
| {Path: "z", NamePos: np("", 7, 8)}}}, |
| nil}, |
| { |
| "FAILImportParensNotClosed", |
| `package testpkg |
| import ( |
| "foo/bar"`, |
| nil, |
| []string{"testfile:3:12 syntax error"}}, |
| } |
| |
| // vdlFileTests contains tests of stuff after the imports. |
| var vdlFileTests = []vdlParseTest{ |
| // Data type tests. |
| { |
| "TypeNamed", |
| `package testpkg |
| type foo bar`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: tn("bar", 2, 10)}}}, |
| nil}, |
| { |
| "TypeNamedQualified", |
| `package testpkg |
| type foo bar.baz`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: tn("bar.baz", 2, 10)}}}, |
| nil}, |
| { |
| "TypeNamedQualifiedPath", |
| `package testpkg |
| type foo "a/b/c/bar".baz`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: tn(`"a/b/c/bar".baz`, 2, 10)}}}, |
| nil}, |
| { |
| "TypeEnum", |
| `package testpkg |
| type foo enum{A;B;C}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeEnum{ |
| Labels: []parse.NamePos{np("A", 2, 15), np("B", 2, 17), np("C", 2, 19)}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeEnumNewlines", |
| `package testpkg |
| type foo enum { |
| A |
| B |
| C |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeEnum{ |
| Labels: []parse.NamePos{np("A", 3, 3), np("B", 4, 3), np("C", 5, 3)}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeArray", |
| `package testpkg |
| type foo [2]bar`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeArray{ |
| Len: 2, Elem: tn("bar", 2, 13), P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeList", |
| `package testpkg |
| type foo []bar`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeList{ |
| Elem: tn("bar", 2, 12), P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeSet", |
| `package testpkg |
| type foo set[bar]`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeSet{ |
| Key: tn("bar", 2, 14), P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeMap", |
| `package testpkg |
| type foo map[bar]baz`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeMap{ |
| Key: tn("bar", 2, 14), Elem: tn("baz", 2, 18), P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructOneField", |
| `package testpkg |
| type foo struct{a b;}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{{NamePos: np("a", 2, 17), Type: tn("b", 2, 19)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructOneFieldNoSemi", |
| `package testpkg |
| type foo struct{a b}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{{NamePos: np("a", 2, 17), Type: tn("b", 2, 19)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructOneFieldNewline", |
| `package testpkg |
| type foo struct{ |
| a b; |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{{NamePos: np("a", 3, 3), Type: tn("b", 3, 5)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructOneFieldNewlineNoSemi", |
| `package testpkg |
| type foo struct{ |
| a b |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{{NamePos: np("a", 3, 3), Type: tn("b", 3, 5)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructOneFieldList", |
| `package testpkg |
| type foo struct{a,b,c d}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{ |
| {NamePos: np("a", 2, 17), Type: tn("d", 2, 23)}, |
| {NamePos: np("b", 2, 19), Type: tn("d", 2, 23)}, |
| {NamePos: np("c", 2, 21), Type: tn("d", 2, 23)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeStructMixed", |
| `package testpkg |
| type foo struct{ |
| a b;c,d e |
| f,g h |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeStruct{ |
| Fields: []*parse.Field{ |
| {NamePos: np("a", 3, 3), Type: tn("b", 3, 5)}, |
| {NamePos: np("c", 3, 7), Type: tn("e", 3, 11)}, |
| {NamePos: np("d", 3, 9), Type: tn("e", 3, 11)}, |
| {NamePos: np("f", 4, 3), Type: tn("h", 4, 7)}, |
| {NamePos: np("g", 4, 5), Type: tn("h", 4, 7)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeUnion", |
| `package testpkg |
| type foo union{A a;B b;C c}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeUnion{ |
| Fields: []*parse.Field{ |
| {NamePos: np("A", 2, 16), Type: tn("a", 2, 18)}, |
| {NamePos: np("B", 2, 20), Type: tn("b", 2, 22)}, |
| {NamePos: np("C", 2, 24), Type: tn("c", 2, 26)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeUnionNewlines", |
| `package testpkg |
| type foo union{ |
| A a |
| B b |
| C c |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeUnion{ |
| Fields: []*parse.Field{ |
| {NamePos: np("A", 3, 3), Type: tn("a", 3, 5)}, |
| {NamePos: np("B", 4, 3), Type: tn("b", 4, 5)}, |
| {NamePos: np("C", 5, 3), Type: tn("c", 5, 5)}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeOptional", |
| `package testpkg |
| type foo union{A a;B ?b;C ?c}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeUnion{ |
| Fields: []*parse.Field{ |
| {NamePos: np("A", 2, 16), Type: tn("a", 2, 18)}, |
| {NamePos: np("B", 2, 20), |
| Type: &parse.TypeOptional{Base: tn("b", 2, 23), P: pos(2, 22)}}, |
| {NamePos: np("C", 2, 25), |
| Type: &parse.TypeOptional{Base: tn("c", 2, 28), P: pos(2, 27)}}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "TypeOptionalNewlines", |
| `package testpkg |
| type foo union{ |
| A a |
| B ?b |
| C ?c |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| TypeDefs: []*parse.TypeDef{ |
| {NamePos: np("foo", 2, 6), Type: &parse.TypeUnion{ |
| Fields: []*parse.Field{ |
| {NamePos: np("A", 3, 3), Type: tn("a", 3, 5)}, |
| {NamePos: np("B", 4, 3), |
| Type: &parse.TypeOptional{Base: tn("b", 4, 6), P: pos(4, 5)}}, |
| {NamePos: np("C", 5, 3), |
| Type: &parse.TypeOptional{Base: tn("c", 5, 6), P: pos(5, 5)}}}, |
| P: pos(2, 10)}}}}, |
| nil}, |
| { |
| "FAILTypeStructNotClosed", |
| `package testpkg |
| type foo struct{ |
| a b`, |
| nil, |
| []string{"testfile:3:6 syntax error"}}, |
| { |
| "FAILTypeStructUnnamedField", |
| `package testpkg |
| type foo struct{a}`, |
| nil, |
| []string{"testfile:2:18 syntax error"}}, |
| { |
| "FAILTypeStructUnnamedFieldList", |
| `package testpkg |
| type foo struct{a, b}`, |
| nil, |
| []string{"testfile:2:21 syntax error"}}, |
| |
| // Const definition tests. |
| { |
| "BoolConst", |
| `package testpkg |
| const foo = true |
| const bar = false`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cn("true", 2, 13)}, |
| {NamePos: np("bar", 3, 7), Expr: cn("false", 3, 13)}}}, |
| nil}, |
| { |
| "StringConst", |
| "package testpkg\nconst foo = \"abc\"\nconst bar = `def`", |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cl("abc", 2, 13)}, |
| {NamePos: np("bar", 3, 7), Expr: cl("def", 3, 13)}}}, |
| nil}, |
| { |
| "IntegerConst", |
| `package testpkg |
| const foo = 123`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cl(big.NewInt(123), 2, 13)}}}, |
| nil}, |
| { |
| "FloatConst", |
| `package testpkg |
| const foo = 1.5`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cl(big.NewRat(3, 2), 2, 13)}}}, |
| nil}, |
| { |
| "NamedConst", |
| `package testpkg |
| const foo = baz |
| const bar = pkg.box`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cn("baz", 2, 13)}, |
| {NamePos: np("bar", 3, 7), Expr: cn("pkg.box", 3, 13)}}}, |
| nil}, |
| { |
| "NamedConstQualified", |
| `package testpkg |
| const foo = bar.baz`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cn("bar.baz", 2, 13)}}}, |
| nil}, |
| { |
| "NamedConstQualifiedPath", |
| `package testpkg |
| const foo = "a/b/c/bar".baz`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: cn(`"a/b/c/bar".baz`, 2, 13)}}}, |
| nil}, |
| { |
| "CompLitConst", |
| `package testpkg |
| const foo = {"a","b"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstCompositeLit{ |
| KVList: []parse.KVLit{ |
| {Value: cl("a", 2, 14)}, |
| {Value: cl("b", 2, 18)}}, |
| P: pos(2, 13)}}}}, |
| nil}, |
| { |
| "CompLitKVConst", |
| `package testpkg |
| const foo = {"a":1,"b":2}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstCompositeLit{ |
| KVList: []parse.KVLit{ |
| {cl("a", 2, 14), cl(big.NewInt(1), 2, 18)}, |
| {cl("b", 2, 20), cl(big.NewInt(2), 2, 24)}}, |
| P: pos(2, 13)}}}}, |
| nil}, |
| { |
| "CompLitTypedConst", |
| `package testpkg |
| const foo = bar{"a","b"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstCompositeLit{ |
| Type: tn("bar", 2, 13), |
| KVList: []parse.KVLit{ |
| {Value: cl("a", 2, 17)}, |
| {Value: cl("b", 2, 21)}}, |
| P: pos(2, 16)}}}}, |
| nil}, |
| { |
| "CompLitKVTypedConst", |
| `package testpkg |
| const foo = bar{"a":1,"b":2}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstCompositeLit{ |
| Type: tn("bar", 2, 13), |
| KVList: []parse.KVLit{ |
| {cl("a", 2, 17), cl(big.NewInt(1), 2, 21)}, |
| {cl("b", 2, 23), cl(big.NewInt(2), 2, 27)}}, |
| P: pos(2, 16)}}}}, |
| nil}, |
| { |
| "UnaryOpConst", |
| `package testpkg |
| const foo = !false |
| const bar = +1 |
| const baz = -2 |
| const box = ^3`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstUnaryOp{ |
| Op: "!", |
| Expr: cn("false", 2, 14), |
| P: pos(2, 13)}, |
| }, |
| {NamePos: np("bar", 3, 7), Expr: &parse.ConstUnaryOp{ |
| Op: "+", |
| Expr: cl(big.NewInt(1), 3, 14), |
| P: pos(3, 13)}, |
| }, |
| {NamePos: np("baz", 4, 7), Expr: &parse.ConstUnaryOp{ |
| Op: "-", |
| Expr: cl(big.NewInt(2), 4, 14), |
| P: pos(4, 13)}, |
| }, |
| {NamePos: np("box", 5, 7), Expr: &parse.ConstUnaryOp{ |
| Op: "^", |
| Expr: cl(big.NewInt(3), 5, 14), |
| P: pos(5, 13), |
| }}}}, |
| nil}, |
| { |
| "TypeConvConst", |
| `package testpkg |
| const foo = baz(true) |
| const bar = pkg.box(false)`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstTypeConv{ |
| Type: tn("baz", 2, 13), |
| Expr: cn("true", 2, 17), |
| P: pos(2, 13), |
| }}, |
| {NamePos: np("bar", 3, 7), Expr: &parse.ConstTypeConv{ |
| Type: tn("pkg.box", 3, 13), |
| Expr: cn("false", 3, 21), |
| P: pos(3, 13), |
| }}}}, |
| nil}, |
| { |
| "TypeObjectConst", |
| `package testpkg |
| const foo = typeobject(bool) |
| const bar = typeobject(pkg.box)`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("foo", 2, 7), Expr: &parse.ConstTypeObject{ |
| Type: tn("bool", 2, 24), |
| P: pos(2, 13), |
| }}, |
| {NamePos: np("bar", 3, 7), Expr: &parse.ConstTypeObject{ |
| Type: tn("pkg.box", 3, 24), |
| P: pos(3, 13), |
| }}}}, |
| nil}, |
| { |
| "BinaryOpConst", |
| `package testpkg |
| const a = true || false |
| const b = true && false |
| const c = 1 < 2 |
| const d = 3 > 4 |
| const e = 5 <= 6 |
| const f = 7 >= 8 |
| const g = 9 != 8 |
| const h = 7 == 6 |
| const i = 5 + 4 |
| const j = 3 - 2 |
| const k = 1 * 2 |
| const l = 3 / 4 |
| const m = 5 % 6 |
| const n = 7 | 8 |
| const o = 9 & 8 |
| const p = 7 ^ 6 |
| const q = 5 << 4 |
| const r = 3 >> 2`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("a", 2, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "||", |
| Lexpr: cn("true", 2, 11), |
| Rexpr: cn("false", 2, 19), |
| P: pos(2, 16), |
| }}, |
| {NamePos: np("b", 3, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "&&", |
| Lexpr: cn("true", 3, 11), |
| Rexpr: cn("false", 3, 19), |
| P: pos(3, 16), |
| }}, |
| {NamePos: np("c", 4, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "<", |
| Lexpr: cl(big.NewInt(1), 4, 11), |
| Rexpr: cl(big.NewInt(2), 4, 15), |
| P: pos(4, 13), |
| }}, |
| {NamePos: np("d", 5, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: ">", |
| Lexpr: cl(big.NewInt(3), 5, 11), |
| Rexpr: cl(big.NewInt(4), 5, 15), |
| P: pos(5, 13), |
| }}, |
| {NamePos: np("e", 6, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "<=", |
| Lexpr: cl(big.NewInt(5), 6, 11), |
| Rexpr: cl(big.NewInt(6), 6, 16), |
| P: pos(6, 13), |
| }}, |
| {NamePos: np("f", 7, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: ">=", |
| Lexpr: cl(big.NewInt(7), 7, 11), |
| Rexpr: cl(big.NewInt(8), 7, 16), |
| P: pos(7, 13), |
| }}, |
| {NamePos: np("g", 8, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "!=", |
| Lexpr: cl(big.NewInt(9), 8, 11), |
| Rexpr: cl(big.NewInt(8), 8, 16), |
| P: pos(8, 13), |
| }}, |
| {NamePos: np("h", 9, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "==", |
| Lexpr: cl(big.NewInt(7), 9, 11), |
| Rexpr: cl(big.NewInt(6), 9, 16), |
| P: pos(9, 13), |
| }}, |
| {NamePos: np("i", 10, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "+", |
| Lexpr: cl(big.NewInt(5), 10, 11), |
| Rexpr: cl(big.NewInt(4), 10, 15), |
| P: pos(10, 13), |
| }}, |
| {NamePos: np("j", 11, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "-", |
| Lexpr: cl(big.NewInt(3), 11, 11), |
| Rexpr: cl(big.NewInt(2), 11, 15), |
| P: pos(11, 13), |
| }}, |
| {NamePos: np("k", 12, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "*", |
| Lexpr: cl(big.NewInt(1), 12, 11), |
| Rexpr: cl(big.NewInt(2), 12, 15), |
| P: pos(12, 13), |
| }}, |
| {NamePos: np("l", 13, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "/", |
| Lexpr: cl(big.NewInt(3), 13, 11), |
| Rexpr: cl(big.NewInt(4), 13, 15), |
| P: pos(13, 13), |
| }}, |
| {NamePos: np("m", 14, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "%", |
| Lexpr: cl(big.NewInt(5), 14, 11), |
| Rexpr: cl(big.NewInt(6), 14, 15), |
| P: pos(14, 13), |
| }}, |
| {NamePos: np("n", 15, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "|", |
| Lexpr: cl(big.NewInt(7), 15, 11), |
| Rexpr: cl(big.NewInt(8), 15, 15), |
| P: pos(15, 13), |
| }}, |
| {NamePos: np("o", 16, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "&", |
| Lexpr: cl(big.NewInt(9), 16, 11), |
| Rexpr: cl(big.NewInt(8), 16, 15), |
| P: pos(16, 13), |
| }}, |
| {NamePos: np("p", 17, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "^", |
| Lexpr: cl(big.NewInt(7), 17, 11), |
| Rexpr: cl(big.NewInt(6), 17, 15), |
| P: pos(17, 13), |
| }}, |
| {NamePos: np("q", 18, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: "<<", |
| Lexpr: cl(big.NewInt(5), 18, 11), |
| Rexpr: cl(big.NewInt(4), 18, 16), |
| P: pos(18, 13), |
| }}, |
| {NamePos: np("r", 19, 7), |
| Expr: &parse.ConstBinaryOp{ |
| Op: ">>", |
| Lexpr: cl(big.NewInt(3), 19, 11), |
| Rexpr: cl(big.NewInt(2), 19, 16), |
| P: pos(19, 13), |
| }}}}, |
| nil}, |
| { |
| "FAILConstOnlyName", |
| `package testpkg |
| const foo`, |
| nil, |
| []string{"testfile:2:10 syntax error"}}, |
| { |
| "FAILConstNoEquals", |
| `package testpkg |
| const foo bar`, |
| nil, |
| []string{"testfile:2:11 syntax error"}}, |
| { |
| "FAILConstNoValue", |
| `package testpkg |
| const foo =`, |
| nil, |
| []string{"testfile:2:12 syntax error"}}, |
| |
| // Error definition tests. |
| { |
| "ErrorEmpty", |
| `package testpkg |
| error()`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9)}, |
| nil}, |
| { |
| "ErrorDefNoParamsNoDetails1", |
| `package testpkg |
| error ErrFoo()`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{NamePos: np("ErrFoo", 2, 7)}}}, |
| nil}, |
| { |
| "ErrorDefNoParamsNoDetails2", |
| `package testpkg |
| error ErrFoo() {}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{NamePos: np("ErrFoo", 2, 7)}}}, |
| nil}, |
| { |
| "ErrorDefNoParamsWithDetails1", |
| `package testpkg |
| error ErrFoo() {NoRetry}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Actions: []parse.StringPos{sp("NoRetry", 2, 17)}}}}, |
| nil}, |
| { |
| "ErrorDefNoParamsWithDetails2", |
| `package testpkg |
| error ErrFoo() {"en":"a"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Formats: []parse.LangFmt{lf(sp("en", 2, 17), sp("a", 2, 22))}}}}, |
| nil}, |
| { |
| "ErrorDefNoParamsWithDetails3", |
| `package testpkg |
| error ErrFoo() {NoRetry, "en":"a", "zh":"b"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Actions: []parse.StringPos{sp("NoRetry", 2, 17)}, |
| Formats: []parse.LangFmt{ |
| lf(sp("en", 2, 26), sp("a", 2, 31)), |
| lf(sp("zh", 2, 36), sp("b", 2, 41)), |
| }}}}, |
| nil}, |
| { |
| "ErrorDefWithParamsNoDetails1", |
| `package testpkg |
| error ErrFoo(x int, y bool)`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 2, 14), Type: tn("int", 2, 16)}, |
| {NamePos: np("y", 2, 21), Type: tn("bool", 2, 23)}}}}}, |
| nil}, |
| { |
| "ErrorDefWithParamsNoDetails2", |
| `package testpkg |
| error ErrFoo(x int, y bool) {}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 2, 14), Type: tn("int", 2, 16)}, |
| {NamePos: np("y", 2, 21), Type: tn("bool", 2, 23)}}}}}, |
| nil}, |
| { |
| "ErrorDefWithParamsWithDetails1", |
| `package testpkg |
| error ErrFoo(x int, y bool) {NoRetry}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 2, 14), Type: tn("int", 2, 16)}, |
| {NamePos: np("y", 2, 21), Type: tn("bool", 2, 23)}}, |
| Actions: []parse.StringPos{sp("NoRetry", 2, 30)}}}}, |
| nil}, |
| { |
| "ErrorDefWithParamsWithDetails2", |
| `package testpkg |
| error ErrFoo(x int, y bool) {"en":"a"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 2, 14), Type: tn("int", 2, 16)}, |
| {NamePos: np("y", 2, 21), Type: tn("bool", 2, 23)}}, |
| Formats: []parse.LangFmt{lf(sp("en", 2, 30), sp("a", 2, 35))}}}}, |
| nil}, |
| { |
| "ErrorDefWithParamsWithDetails3", |
| `package testpkg |
| error ErrFoo(x int, y bool) {NoRetry, "en":"a", "zh":"b"}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{{ |
| NamePos: np("ErrFoo", 2, 7), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 2, 14), Type: tn("int", 2, 16)}, |
| {NamePos: np("y", 2, 21), Type: tn("bool", 2, 23)}}, |
| Actions: []parse.StringPos{sp("NoRetry", 2, 30)}, |
| Formats: []parse.LangFmt{ |
| lf(sp("en", 2, 39), sp("a", 2, 44)), |
| lf(sp("zh", 2, 49), sp("b", 2, 54)), |
| }}}}, |
| nil}, |
| { |
| "ErrorDefMulti", |
| `package testpkg |
| error ( |
| ErrFoo() |
| ErrBar() {NoRetry, "en":"a", "zh":"b"} |
| ErrBaz(x int, y bool) {NoRetry, "en":"a", "zh":"b"} |
| )`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| ErrorDefs: []*parse.ErrorDef{ |
| { |
| NamePos: np("ErrFoo", 3, 3), |
| }, |
| { |
| NamePos: np("ErrBar", 4, 3), |
| Actions: []parse.StringPos{sp("NoRetry", 4, 13)}, |
| Formats: []parse.LangFmt{ |
| lf(sp("en", 4, 22), sp("a", 4, 27)), |
| lf(sp("zh", 4, 32), sp("b", 4, 37)), |
| }, |
| }, |
| { |
| NamePos: np("ErrBaz", 5, 3), |
| Params: []*parse.Field{ |
| {NamePos: np("x", 5, 10), Type: tn("int", 5, 12)}, |
| {NamePos: np("y", 5, 17), Type: tn("bool", 5, 19)}}, |
| Actions: []parse.StringPos{sp("NoRetry", 5, 26)}, |
| Formats: []parse.LangFmt{ |
| lf(sp("en", 5, 35), sp("a", 5, 40)), |
| lf(sp("zh", 5, 45), sp("b", 5, 50)), |
| }, |
| }, |
| }}, |
| nil}, |
| |
| // Interface tests. |
| { |
| "InterfaceEmpty", |
| `package testpkg |
| type foo interface{}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6)}}}, |
| nil}, |
| { |
| "InterfaceOneMethodOneInUnnamedOut", |
| `package testpkg |
| type foo interface{meth1(a b) (c | error)}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Methods: []*parse.Method{{NamePos: np("meth1", 2, 20), |
| InArgs: []*parse.Field{{NamePos: np("a", 2, 26), Type: tn("b", 2, 28)}}, |
| OutArgs: []*parse.Field{{NamePos: np("", 2, 32), Type: tn("c", 2, 32)}}}}}}}, |
| nil}, |
| { |
| "InterfaceErrors", |
| `package testpkg |
| type foo interface{meth1(err error) error}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Methods: []*parse.Method{{NamePos: np("meth1", 2, 20), |
| InArgs: []*parse.Field{{NamePos: np("err", 2, 26), Type: tn("error", 2, 30)}}}}}}}, |
| nil}, |
| { |
| "InterfaceMixedMethods", |
| `package testpkg |
| type foo interface{ |
| meth1(a b) (c | error);meth2() error |
| meth3(e f, g, h i) (j k, l, m n | error) |
| }`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Methods: []*parse.Method{ |
| {NamePos: np("meth1", 3, 3), |
| InArgs: []*parse.Field{{NamePos: np("a", 3, 9), Type: tn("b", 3, 11)}}, |
| OutArgs: []*parse.Field{{NamePos: np("", 3, 15), Type: tn("c", 3, 15)}}}, |
| {NamePos: np("meth2", 3, 26)}, |
| {NamePos: np("meth3", 4, 3), |
| InArgs: []*parse.Field{ |
| {NamePos: np("e", 4, 9), Type: tn("f", 4, 11)}, |
| {NamePos: np("g", 4, 14), Type: tn("i", 4, 19)}, |
| {NamePos: np("h", 4, 17), Type: tn("i", 4, 19)}}, |
| OutArgs: []*parse.Field{ |
| {NamePos: np("j", 4, 23), Type: tn("k", 4, 25)}, |
| {NamePos: np("l", 4, 28), Type: tn("n", 4, 33)}, |
| {NamePos: np("m", 4, 31), Type: tn("n", 4, 33)}}}}}}}, |
| nil}, |
| { |
| "InterfaceEmbed", |
| `package testpkg |
| type foo interface{bar}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Embeds: []*parse.NamePos{npptr("bar", 2, 20)}}}}, |
| nil}, |
| { |
| "InterfaceEmbedQualified", |
| `package testpkg |
| type foo interface{bar.baz}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Embeds: []*parse.NamePos{npptr("bar.baz", 2, 20)}}}}, |
| nil}, |
| { |
| "InterfaceEmbedQualifiedPath", |
| `package testpkg |
| type foo interface{"a/b/c/bar".baz}`, |
| &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 1, 9), |
| Interfaces: []*parse.Interface{{NamePos: np("foo", 2, 6), |
| Embeds: []*parse.NamePos{npptr(`"a/b/c/bar".baz`, 2, 20)}}}}, |
| nil}, |
| { |
| "FAILInterfaceUnclosedInterface", |
| `package testpkg |
| type foo interface{ |
| meth1()`, |
| nil, |
| []string{"testfile:3:10 syntax error"}}, |
| { |
| "FAILInterfaceUnclosedArgs", |
| `package testpkg |
| type foo interface{ |
| meth1( |
| }`, |
| nil, |
| []string{"testfile:4:1 syntax error"}}, |
| { |
| "FAILInterfaceVariableNames", |
| `package testpkg |
| type foo interface{ |
| meth1([]a, []b []c) |
| }`, |
| nil, |
| []string{"expected one or more variable names", |
| "testfile:3:18 perhaps you forgot a comma"}}, |
| } |
| |
| // configTests contains tests of config files. |
| var configTests = []configTest{ |
| // Empty file isn't allowed (need at least a package clause). |
| { |
| "FAILEmptyFile", |
| "", |
| nil, |
| []string{"config file must start with config clause"}}, |
| |
| // Comment tests. |
| { |
| "ConfigDocOneLiner", |
| `// One liner |
| // Another line |
| config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: parse.NamePos{Name: "config", Pos: pos(3, 1), Doc: `// One liner |
| // Another line |
| `}, |
| Config: cn("true", 3, 10)}, |
| nil}, |
| { |
| "ConfigDocMultiLiner", |
| `/* Multi liner |
| Another line |
| */ |
| config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: parse.NamePos{Name: "config", Pos: pos(4, 1), Doc: `/* Multi liner |
| Another line |
| */ |
| `}, |
| Config: cn("true", 4, 10)}, |
| nil}, |
| { |
| "FileDocNoConfigDoc", |
| `// File doc, has extra newline so not config doc |
| |
| config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 3, 1), |
| Doc: "// File doc, has extra newline so not config doc\n", |
| Config: cn("true", 3, 10)}, |
| nil}, |
| { |
| "FileDocAndConfigDoc", |
| `// File doc |
| |
| // Config doc |
| config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: parse.NamePos{Name: "config", Pos: pos(4, 1), Doc: "// Config doc\n"}, |
| Doc: "// File doc\n", |
| Config: cn("true", 4, 10)}, |
| nil}, |
| { |
| "FAILUnterminatedComment", |
| `/* Unterminated |
| Another line |
| config = true`, |
| nil, |
| []string{"comment not terminated"}}, |
| |
| // Config tests. |
| { |
| "Config", |
| "config = true;", |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("true", 1, 10)}, |
| nil}, |
| { |
| "ConfigNoSemi", |
| "config = true", |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("true", 1, 10)}, |
| nil}, |
| { |
| "ConfigNamedConfig", |
| "config = config", |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("config", 1, 10)}, |
| nil}, |
| { |
| "FAILConfigNoEqual", |
| "config true", |
| nil, |
| []string{"testfile:1:8 syntax error"}}, |
| |
| // Import tests. |
| { |
| "EmptyImport", |
| `config = foo |
| import ( |
| )`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "OneImport", |
| `config = foo |
| import "foo/bar";`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 2, 8)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "OneImportLocalNameNoSemi", |
| `config = foo |
| import baz "foo/bar"`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("baz", 2, 8)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "OneImportParens", |
| `config = foo |
| import ( |
| "foo/bar"; |
| )`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 3, 3)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "OneImportParensNoSemi", |
| `config = foo |
| import ( |
| "foo/bar" |
| )`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("", 3, 3)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "OneImportParensNamed", |
| `config = foo |
| import ( |
| baz "foo/bar" |
| )`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo/bar", NamePos: np("baz", 3, 3)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "MixedImports", |
| `config = foo |
| import "foo/bar" |
| import ( |
| "baz";"a/b" |
| "c/d" |
| ) |
| import "z"`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{ |
| {Path: "foo/bar", NamePos: np("", 2, 8)}, |
| {Path: "baz", NamePos: np("", 4, 3)}, |
| {Path: "a/b", NamePos: np("", 4, 9)}, |
| {Path: "c/d", NamePos: np("", 5, 3)}, |
| {Path: "z", NamePos: np("", 7, 8)}}, |
| Config: cn("foo", 1, 10)}, |
| nil}, |
| { |
| "FAILImportParensNotClosed", |
| `config = foo |
| import ( |
| "foo/bar"`, |
| nil, |
| []string{"testfile:3:12 syntax error"}}, |
| |
| // Inline config tests. |
| { |
| "BoolConst", |
| `config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("true", 1, 10)}, |
| nil}, |
| { |
| "StringConst", |
| `config = "abc"`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cl("abc", 1, 10)}, |
| nil}, |
| { |
| "IntegerConst", |
| `config = 123`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cl(big.NewInt(123), 1, 10)}, |
| nil}, |
| { |
| "FloatConst", |
| `config = 1.5`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cl(big.NewRat(3, 2), 1, 10)}, |
| nil}, |
| { |
| "NamedConst", |
| `config = pkg.foo`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: cn("pkg.foo", 1, 10)}, |
| nil}, |
| { |
| "CompLitConst", |
| `config = {"a","b"}`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: &parse.ConstCompositeLit{ |
| KVList: []parse.KVLit{ |
| {Value: cl("a", 1, 11)}, |
| {Value: cl("b", 1, 15)}}, |
| P: pos(1, 10)}}, |
| nil}, |
| { |
| "CompLitKVConst", |
| `config = {"a":1,"b":2}`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: &parse.ConstCompositeLit{ |
| KVList: []parse.KVLit{ |
| {cl("a", 1, 11), cl(big.NewInt(1), 1, 15)}, |
| {cl("b", 1, 17), cl(big.NewInt(2), 1, 21)}}, |
| P: pos(1, 10)}}, |
| nil}, |
| { |
| "CompLitTypedConst", |
| `config = foo{"a","b"}`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: &parse.ConstCompositeLit{ |
| Type: tn("foo", 1, 10), |
| KVList: []parse.KVLit{ |
| {Value: cl("a", 1, 14)}, |
| {Value: cl("b", 1, 18)}}, |
| P: pos(1, 13)}}, |
| nil}, |
| { |
| "CompLitKVTypedConst", |
| `config = foo{"a":1,"b":2}`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Config: &parse.ConstCompositeLit{ |
| Type: tn("foo", 1, 10), |
| KVList: []parse.KVLit{ |
| {cl("a", 1, 14), cl(big.NewInt(1), 1, 18)}, |
| {cl("b", 1, 20), cl(big.NewInt(2), 1, 24)}}, |
| P: pos(1, 13)}}, |
| nil}, |
| { |
| "FAILConstNoEquals", |
| `config 123`, |
| nil, |
| []string{"testfile:1:8 syntax error"}}, |
| { |
| "FAILConstNoValue", |
| `config =`, |
| nil, |
| []string{"testfile:1:9 syntax error"}}, |
| |
| // Out-of-line config tests. |
| { |
| "BoolOutOfLineConfig", |
| `config = config |
| import "foo" |
| const config = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo", NamePos: np("", 2, 8)}}, |
| Config: cn("config", 1, 10), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("config", 3, 7), Expr: cn("true", 3, 16)}}}, |
| nil}, |
| { |
| "BoolOutOfLineBar", |
| `config = bar |
| import "foo" |
| const bar = true`, |
| &parse.Config{FileName: "testfile", ConfigDef: np("config", 1, 1), |
| Imports: []*parse.Import{{Path: "foo", NamePos: np("", 2, 8)}}, |
| Config: cn("bar", 1, 10), |
| ConstDefs: []*parse.ConstDef{ |
| {NamePos: np("bar", 3, 7), Expr: cn("true", 3, 13)}}}, |
| nil}, |
| |
| // Errors, types and interfaces return error |
| { |
| "FAILError", |
| `config = true |
| error foo()`, |
| nil, |
| []string{"config files may not contain error, type or interface definitions"}}, |
| { |
| "FAILType", |
| `config = true |
| type foo bool`, |
| nil, |
| []string{"config files may not contain error, type or interface definitions"}}, |
| { |
| "FAILInterface", |
| `config = true |
| type foo interface{}`, |
| nil, |
| []string{"config files may not contain error, type or interface definitions"}}, |
| } |
| |
| func configImports(imports ...string) *parse.Config { |
| config := new(parse.Config) |
| for _, i := range imports { |
| config.Imports = append(config.Imports, &parse.Import{Path: i}) |
| } |
| return config |
| } |
| |
| func TestConfigHasImport(t *testing.T) { |
| config := configImports("a", "b/c") |
| tests := []struct { |
| Path string |
| Want bool |
| }{ |
| {"a", true}, |
| {"b/c", true}, |
| {"b", false}, |
| {"c", false}, |
| {"d", false}, |
| } |
| for _, test := range tests { |
| if got, want := config.HasImport(test.Path), test.Want; got != want { |
| t.Errorf("HasImport(%q) got %v, want %v", test.Path, got, want) |
| } |
| } |
| } |
| |
| func TestConfigAddImports(t *testing.T) { |
| tests := []struct { |
| Base *parse.Config |
| Imports []string |
| Want *parse.Config |
| }{ |
| {configImports(), []string{"a", "b/c"}, configImports("a", "b/c")}, |
| {configImports("a"), []string{"a", "b/c"}, configImports("a", "b/c")}, |
| {configImports("a", "b/c"), []string{"a", "b/c"}, configImports("a", "b/c")}, |
| {configImports("a", "b/c"), []string{"a", "b/c", "d"}, configImports("a", "b/c", "d")}, |
| } |
| for _, test := range tests { |
| test.Base.AddImports(test.Imports...) |
| if got, want := test.Base, test.Want; !reflect.DeepEqual(got, want) { |
| t.Errorf("AddImports(%q) got %v, want %v", test.Imports, got, want) |
| } |
| } |
| } |
| |
| func TestParseExprs(t *testing.T) { |
| tests := []struct { |
| Data string |
| Exprs []parse.ConstExpr |
| Err string |
| }{ |
| {``, nil, "syntax error"}, |
| {`true`, []parse.ConstExpr{cn("true", 1, 1)}, ""}, |
| {`false`, []parse.ConstExpr{cn("false", 1, 1)}, ""}, |
| {`abc`, []parse.ConstExpr{cn("abc", 1, 1)}, ""}, |
| {`"a/b/c".abc`, []parse.ConstExpr{cn(`"a/b/c".abc`, 1, 1)}, ""}, |
| {`"abc"`, []parse.ConstExpr{cl("abc", 1, 1)}, ""}, |
| {`1`, []parse.ConstExpr{cl(big.NewInt(1), 1, 1)}, ""}, |
| {`123`, []parse.ConstExpr{cl(big.NewInt(123), 1, 1)}, ""}, |
| {`1.0`, []parse.ConstExpr{cl(big.NewRat(1, 1), 1, 1)}, ""}, |
| {`1.5`, []parse.ConstExpr{cl(big.NewRat(3, 2), 1, 1)}, ""}, |
| {`{1,2}`, []parse.ConstExpr{ |
| &parse.ConstCompositeLit{ |
| KVList: []parse.KVLit{ |
| {Value: cl(big.NewInt(1), 1, 2)}, |
| {Value: cl(big.NewInt(2), 1, 4)}, |
| }, |
| P: pos(1, 1), |
| }, |
| }, ""}, |
| {`1+2`, []parse.ConstExpr{ |
| &parse.ConstBinaryOp{"+", |
| cl(big.NewInt(1), 1, 1), |
| cl(big.NewInt(2), 1, 3), |
| pos(1, 2), |
| }, |
| }, ""}, |
| {`1,"abc"`, []parse.ConstExpr{ |
| cl(big.NewInt(1), 1, 1), |
| cl("abc", 1, 3), |
| }, ""}, |
| } |
| for _, test := range tests { |
| errs := vdlutil.NewErrors(-1) |
| exprs := parse.ParseExprs(test.Data, errs) |
| vdltestutil.ExpectResult(t, errs, test.Data, test.Err) |
| if got, want := exprs, test.Exprs; !reflect.DeepEqual(got, want) { |
| t.Errorf("%s got %v, want %v", test.Data, got, want) |
| } |
| } |
| } |