mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-29 01:11:02 +02:00
Preparation for linter.
* Extract some test utilities to a separate package. * Rename some test utilities. * Internally expose DirectChildren. * Add LocationRange to some non-expr AST parts, such as local binds, parameters and object fields. * Add end-of-file-reached testcases.
This commit is contained in:
parent
724650d358
commit
3a245f70d4
@ -45,6 +45,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//ast:go_default_library",
|
"//ast:go_default_library",
|
||||||
"//internal/parser:go_default_library",
|
"//internal/parser:go_default_library",
|
||||||
"@com_github_sergi_go_diff//diffmatchpatch:go_default_library",
|
"//internal/testutils:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -394,6 +394,7 @@ type Parameter struct {
|
|||||||
EqFodder Fodder
|
EqFodder Fodder
|
||||||
DefaultArg Node
|
DefaultArg Node
|
||||||
CommaFodder Fodder
|
CommaFodder Fodder
|
||||||
|
LocRange LocationRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommaSeparatedID represents an expression that is an element of a
|
// CommaSeparatedID represents an expression that is an element of a
|
||||||
@ -468,6 +469,8 @@ type LocalBind struct {
|
|||||||
Fun *Function
|
Fun *Function
|
||||||
// The fodder before the closing ',' or ';' (whichever it is)
|
// The fodder before the closing ',' or ';' (whichever it is)
|
||||||
CloseFodder Fodder
|
CloseFodder Fodder
|
||||||
|
|
||||||
|
LocRange LocationRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalBinds represents a LocalBind slice.
|
// LocalBinds represents a LocalBind slice.
|
||||||
@ -594,15 +597,17 @@ type ObjectField struct {
|
|||||||
OpFodder Fodder
|
OpFodder Fodder
|
||||||
Expr2, Expr3 Node // In scope of the object (can see self).
|
Expr2, Expr3 Node // In scope of the object (can see self).
|
||||||
CommaFodder Fodder
|
CommaFodder Fodder
|
||||||
|
LocRange LocationRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectFieldLocalNoMethod creates a non-method local object field.
|
// ObjectFieldLocalNoMethod creates a non-method local object field.
|
||||||
func ObjectFieldLocalNoMethod(id *Identifier, body Node) ObjectField {
|
func ObjectFieldLocalNoMethod(id *Identifier, body Node, loc LocationRange) ObjectField {
|
||||||
return ObjectField{
|
return ObjectField{
|
||||||
Kind: ObjectLocal,
|
Kind: ObjectLocal,
|
||||||
Hide: ObjectFieldVisible,
|
Hide: ObjectFieldVisible,
|
||||||
Id: id,
|
Id: id,
|
||||||
Expr2: body,
|
Expr2: body,
|
||||||
|
LocRange: loc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,6 +633,8 @@ type DesugaredObjectField struct {
|
|||||||
Name Node
|
Name Node
|
||||||
Body Node
|
Body Node
|
||||||
PlusSuper bool
|
PlusSuper bool
|
||||||
|
|
||||||
|
LocRange LocationRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// DesugaredObjectFields represents a DesugaredObjectField slice.
|
// DesugaredObjectFields represents a DesugaredObjectField slice.
|
||||||
|
@ -30,14 +30,14 @@ const anonymous = "anonymous"
|
|||||||
// package or a separate internal astutils package. The only reason I'm not doing it
|
// package or a separate internal astutils package. The only reason I'm not doing it
|
||||||
// right now is that it's a pretty invasive change that deserves a separate PR.
|
// right now is that it's a pretty invasive change that deserves a separate PR.
|
||||||
|
|
||||||
// directChildren are children of AST node that are executed in the same context
|
// DirectChildren are children of AST node that are executed in the same context
|
||||||
// and environment as their parent. It supports ASTs before and after desugaring.
|
// and environment as their parent. It supports ASTs before and after desugaring.
|
||||||
//
|
//
|
||||||
// They must satisfy the following rules:
|
// They must satisfy the following rules:
|
||||||
// * (no-delayed-evaluation) They are evaluated when their parent is evaluated or never.
|
// * (no-delayed-evaluation) They are evaluated when their parent is evaluated or never.
|
||||||
// * (no-indirect-evaluation) They cannot be evaluated during evaluation of any non-direct children
|
// * (no-indirect-evaluation) They cannot be evaluated during evaluation of any non-direct children
|
||||||
// * (same-environment) They must be evaluated in the same environment as their parent
|
// * (same-environment) They must be evaluated in the same environment as their parent
|
||||||
func directChildren(node ast.Node) []ast.Node {
|
func DirectChildren(node ast.Node) []ast.Node {
|
||||||
switch node := node.(type) {
|
switch node := node.(type) {
|
||||||
case *ast.Apply:
|
case *ast.Apply:
|
||||||
return []ast.Node{node.Target}
|
return []ast.Node{node.Target}
|
||||||
@ -354,7 +354,7 @@ func specialChildren(node ast.Node) []ast.Node {
|
|||||||
// Children returns all children of a node. It supports ASTs before and after desugaring.
|
// Children returns all children of a node. It supports ASTs before and after desugaring.
|
||||||
func Children(node ast.Node) []ast.Node {
|
func Children(node ast.Node) []ast.Node {
|
||||||
var result []ast.Node
|
var result []ast.Node
|
||||||
result = append(result, directChildren(node)...)
|
result = append(result, DirectChildren(node)...)
|
||||||
result = append(result, thunkChildren(node)...)
|
result = append(result, thunkChildren(node)...)
|
||||||
result = append(result, specialChildren(node)...)
|
result = append(result, specialChildren(node)...)
|
||||||
return result
|
return result
|
||||||
@ -400,7 +400,7 @@ func addContext(node ast.Node, context *string, bind string) {
|
|||||||
case *ast.Object:
|
case *ast.Object:
|
||||||
// TODO(sbarzowski) include fieldname, maybe even chains
|
// TODO(sbarzowski) include fieldname, maybe even chains
|
||||||
|
|
||||||
outOfObject := directChildren(node)
|
outOfObject := DirectChildren(node)
|
||||||
for _, f := range outOfObject {
|
for _, f := range outOfObject {
|
||||||
// This actually is evaluated outside of object
|
// This actually is evaluated outside of object
|
||||||
addContext(f, context, anonymous)
|
addContext(f, context, anonymous)
|
||||||
@ -414,7 +414,7 @@ func addContext(node ast.Node, context *string, bind string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.ObjectComp:
|
case *ast.ObjectComp:
|
||||||
outOfObject := directChildren(node)
|
outOfObject := DirectChildren(node)
|
||||||
for _, f := range outOfObject {
|
for _, f := range outOfObject {
|
||||||
// This actually is evaluated outside of object
|
// This actually is evaluated outside of object
|
||||||
addContext(f, context, anonymous)
|
addContext(f, context, anonymous)
|
||||||
@ -438,7 +438,7 @@ func addContext(node ast.Node, context *string, bind string) {
|
|||||||
}
|
}
|
||||||
addContext(node.Body, context, bind)
|
addContext(node.Body, context, bind)
|
||||||
default:
|
default:
|
||||||
for _, child := range directChildren(node) {
|
for _, child := range DirectChildren(node) {
|
||||||
addContext(child, context, anonymous)
|
addContext(child, context, anonymous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +209,7 @@ func (p *parser) parseParameter() (ast.Parameter, errors.StaticError) {
|
|||||||
}
|
}
|
||||||
ret.Name = ast.Identifier(ident.data)
|
ret.Name = ast.Identifier(ident.data)
|
||||||
ret.NameFodder = ident.fodder
|
ret.NameFodder = ident.fodder
|
||||||
|
ret.LocRange = ident.loc
|
||||||
if p.peek().kind == tokenOperator && p.peek().data == "=" {
|
if p.peek().kind == tokenOperator && p.peek().data == "=" {
|
||||||
eq := p.pop()
|
eq := p.pop()
|
||||||
ret.EqFodder = eq.fodder
|
ret.EqFodder = eq.fodder
|
||||||
@ -216,6 +217,7 @@ func (p *parser) parseParameter() (ast.Parameter, errors.StaticError) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
ret.LocRange = locFromTokenAST(ident, ret.DefaultArg)
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
@ -312,6 +314,7 @@ func (p *parser) parseBind(binds *ast.LocalBinds) (*token, errors.StaticError) {
|
|||||||
Body: body,
|
Body: body,
|
||||||
Fun: fun,
|
Fun: fun,
|
||||||
CloseFodder: delim.fodder,
|
CloseFodder: delim.fodder,
|
||||||
|
LocRange: locFromTokenAST(varID, body),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
*binds = append(*binds, ast.LocalBind{
|
*binds = append(*binds, ast.LocalBind{
|
||||||
@ -320,6 +323,7 @@ func (p *parser) parseBind(binds *ast.LocalBinds) (*token, errors.StaticError) {
|
|||||||
EqFodder: eqToken.fodder,
|
EqFodder: eqToken.fodder,
|
||||||
Body: body,
|
Body: body,
|
||||||
CloseFodder: delim.fodder,
|
CloseFodder: delim.fodder,
|
||||||
|
LocRange: locFromTokenAST(varID, body),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,6 +509,7 @@ func (p *parser) parseObjectRemainderField(literalFields *LiteralFieldSet, tok *
|
|||||||
OpFodder: opFodder,
|
OpFodder: opFodder,
|
||||||
Expr2: body,
|
Expr2: body,
|
||||||
CommaFodder: commaFodder,
|
CommaFodder: commaFodder,
|
||||||
|
LocRange: locFromTokenAST(next, body),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,6 +580,7 @@ func (p *parser) parseObjectRemainderLocal(binds *ast.IdentifierSet, tok *token,
|
|||||||
OpFodder: opToken.fodder,
|
OpFodder: opToken.fodder,
|
||||||
Expr2: body,
|
Expr2: body,
|
||||||
CommaFodder: commaFodder,
|
CommaFodder: commaFodder,
|
||||||
|
LocRange: locFromTokenAST(varID, body),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,6 +589,7 @@ func (p *parser) parseObjectRemainderAssert(tok *token, next *token) (*ast.Objec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
lastAST := cond // for determining location
|
||||||
var msg ast.Node
|
var msg ast.Node
|
||||||
var colonFodder ast.Fodder
|
var colonFodder ast.Fodder
|
||||||
if p.peek().kind == tokenOperator && p.peek().data == ":" {
|
if p.peek().kind == tokenOperator && p.peek().data == ":" {
|
||||||
@ -592,6 +599,7 @@ func (p *parser) parseObjectRemainderAssert(tok *token, next *token) (*ast.Objec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
lastAST = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
var commaFodder ast.Fodder
|
var commaFodder ast.Fodder
|
||||||
@ -607,6 +615,7 @@ func (p *parser) parseObjectRemainderAssert(tok *token, next *token) (*ast.Objec
|
|||||||
OpFodder: colonFodder,
|
OpFodder: colonFodder,
|
||||||
Expr3: msg,
|
Expr3: msg,
|
||||||
CommaFodder: commaFodder,
|
CommaFodder: commaFodder,
|
||||||
|
LocRange: locFromTokenAST(next, lastAST),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,9 @@ func desugarFields(nodeBase ast.NodeBase, fields *ast.ObjectFields, objLevel int
|
|||||||
}
|
}
|
||||||
onFailure := &ast.Error{Expr: msg}
|
onFailure := &ast.Error{Expr: msg}
|
||||||
asserts = append(asserts, &ast.Conditional{
|
asserts = append(asserts, &ast.Conditional{
|
||||||
|
NodeBase: ast.NodeBase{
|
||||||
|
LocRange: field.LocRange,
|
||||||
|
},
|
||||||
Cond: field.Expr2,
|
Cond: field.Expr2,
|
||||||
BranchTrue: &ast.LiteralBoolean{Value: true}, // ignored anyway
|
BranchTrue: &ast.LiteralBoolean{Value: true}, // ignored anyway
|
||||||
BranchFalse: onFailure,
|
BranchFalse: onFailure,
|
||||||
@ -74,6 +77,7 @@ func desugarFields(nodeBase ast.NodeBase, fields *ast.ObjectFields, objLevel int
|
|||||||
Name: makeStr(string(*field.Id)),
|
Name: makeStr(string(*field.Id)),
|
||||||
Body: field.Expr2,
|
Body: field.Expr2,
|
||||||
PlusSuper: field.SuperSugar,
|
PlusSuper: field.SuperSugar,
|
||||||
|
LocRange: field.LocRange,
|
||||||
})
|
})
|
||||||
|
|
||||||
case ast.ObjectFieldExpr, ast.ObjectFieldStr:
|
case ast.ObjectFieldExpr, ast.ObjectFieldStr:
|
||||||
@ -82,12 +86,14 @@ func desugarFields(nodeBase ast.NodeBase, fields *ast.ObjectFields, objLevel int
|
|||||||
Name: field.Expr1,
|
Name: field.Expr1,
|
||||||
Body: field.Expr2,
|
Body: field.Expr2,
|
||||||
PlusSuper: field.SuperSugar,
|
PlusSuper: field.SuperSugar,
|
||||||
|
LocRange: field.LocRange,
|
||||||
})
|
})
|
||||||
|
|
||||||
case ast.ObjectLocal:
|
case ast.ObjectLocal:
|
||||||
locals = append(locals, ast.LocalBind{
|
locals = append(locals, ast.LocalBind{
|
||||||
Variable: *field.Id,
|
Variable: *field.Id,
|
||||||
Body: ast.Clone(field.Expr2), // TODO(sbarzowski) not sure if clone is needed
|
Body: ast.Clone(field.Expr2), // TODO(sbarzowski) not sure if clone is needed
|
||||||
|
LocRange: field.LocRange,
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unexpected object field kind %v", field.Kind))
|
panic(fmt.Sprintf("Unexpected object field kind %v", field.Kind))
|
||||||
|
9
internal/testutils/BUILD.bazel
Normal file
9
internal/testutils/BUILD.bazel
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["test_utils.go"],
|
||||||
|
importpath = "github.com/google/go-jsonnet/internal/testutils",
|
||||||
|
visibility = ["//:__subpackages__"],
|
||||||
|
deps = ["@com_github_sergi_go_diff//diffmatchpatch:go_default_library"],
|
||||||
|
)
|
45
internal/testutils/test_utils.go
Normal file
45
internal/testutils/test_utils.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package testutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Diff produces a pretty diff of two files
|
||||||
|
func Diff(a, b string) string {
|
||||||
|
dmp := diffmatchpatch.New()
|
||||||
|
diffs := dmp.DiffMain(a, b, false)
|
||||||
|
return dmp.DiffPrettyText(diffs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompareWithGolden check if a file is the same as golden file.
|
||||||
|
// If it is not it produces a pretty diff.
|
||||||
|
func CompareWithGolden(result string, golden []byte) (string, bool) {
|
||||||
|
if !bytes.Equal(golden, []byte(result)) {
|
||||||
|
// TODO(sbarzowski) better reporting of differences in whitespace
|
||||||
|
// missing newline issues can be very subtle now
|
||||||
|
return Diff(result, string(golden)), true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGoldenFile updates a golden file with new contents if the new contents
|
||||||
|
// are actually different from what is already there. It returns whether or not
|
||||||
|
// the overwrite was performed (i.e. the desired content was different than actual).
|
||||||
|
func UpdateGoldenFile(path string, content []byte, mode os.FileMode) (changed bool, err error) {
|
||||||
|
old, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// If it exists and already has the right content, do nothing,
|
||||||
|
if bytes.Equal(old, content) && !os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path, content, mode); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
39
main_test.go
39
main_test.go
@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-jsonnet/ast"
|
"github.com/google/go-jsonnet/ast"
|
||||||
"github.com/google/go-jsonnet/internal/parser"
|
"github.com/google/go-jsonnet/internal/parser"
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
"github.com/google/go-jsonnet/internal/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var update = flag.Bool("update", false, "update .golden files")
|
var update = flag.Bool("update", false, "update .golden files")
|
||||||
@ -215,29 +215,6 @@ func runJsonnet(i jsonnetInput) jsonnetResult {
|
|||||||
return runInternalJsonnet(i)
|
return runInternalJsonnet(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareGolden(result string, golden []byte) (string, bool) {
|
|
||||||
if !bytes.Equal(golden, []byte(result)) {
|
|
||||||
// TODO(sbarzowski) better reporting of differences in whitespace
|
|
||||||
// missing newline issues can be very subtle now
|
|
||||||
return diff(result, string(golden)), true
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(path string, content []byte, mode os.FileMode) (changed bool, err error) {
|
|
||||||
old, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if bytes.Equal(old, content) && !os.IsNotExist(err) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(path, content, mode); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareSingleGolden(path string, result jsonnetResult) []error {
|
func compareSingleGolden(path string, result jsonnetResult) []error {
|
||||||
if result.outputMulti != nil {
|
if result.outputMulti != nil {
|
||||||
return []error{fmt.Errorf("outputMulti is populated in a single-file test for %v", path)}
|
return []error{fmt.Errorf("outputMulti is populated in a single-file test for %v", path)}
|
||||||
@ -246,7 +223,7 @@ func compareSingleGolden(path string, result jsonnetResult) []error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{fmt.Errorf("reading file %s: %v", path, err)}
|
return []error{fmt.Errorf("reading file %s: %v", path, err)}
|
||||||
}
|
}
|
||||||
if diff, hasDiff := compareGolden(result.output, golden); hasDiff {
|
if diff, hasDiff := testutils.CompareWithGolden(result.output, golden); hasDiff {
|
||||||
return []error{fmt.Errorf("golden file %v has diff:\n%v", path, diff)}
|
return []error{fmt.Errorf("golden file %v has diff:\n%v", path, diff)}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -256,7 +233,7 @@ func updateSingleGolden(path string, result jsonnetResult) (updated []string, er
|
|||||||
if result.outputMulti != nil {
|
if result.outputMulti != nil {
|
||||||
return nil, fmt.Errorf("outputMulti is populated in a single-file test for %v", path)
|
return nil, fmt.Errorf("outputMulti is populated in a single-file test for %v", path)
|
||||||
}
|
}
|
||||||
changed, err := writeFile(path, []byte(result.output), 0666)
|
changed, err := testutils.UpdateGoldenFile(path, []byte(result.output), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("updating golden file %v: %v", path, err)
|
return nil, fmt.Errorf("updating golden file %v: %v", path, err)
|
||||||
}
|
}
|
||||||
@ -289,7 +266,7 @@ func compareMultifileGolden(path string, result jsonnetResult) []error {
|
|||||||
errs = append(errs, fmt.Errorf("jsonnet outputted file %v which does not exist in goldens", fn))
|
errs = append(errs, fmt.Errorf("jsonnet outputted file %v which does not exist in goldens", fn))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if diff, hasDiff := compareGolden(content, goldenContent[fn]); hasDiff {
|
if diff, hasDiff := testutils.CompareWithGolden(content, goldenContent[fn]); hasDiff {
|
||||||
errs = append(errs, fmt.Errorf("golden file %v has diff:\n%v", fn, diff))
|
errs = append(errs, fmt.Errorf("golden file %v has diff:\n%v", fn, diff))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,7 +280,7 @@ func updateMultifileGolden(path string, result jsonnetResult) ([]string, error)
|
|||||||
}
|
}
|
||||||
var updatedFiles []string
|
var updatedFiles []string
|
||||||
for fn, content := range result.outputMulti {
|
for fn, content := range result.outputMulti {
|
||||||
updated, err := writeFile(filepath.Join(path, fn), []byte(content), 0666)
|
updated, err := testutils.UpdateGoldenFile(filepath.Join(path, fn), []byte(content), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("updating golden file %v: %v", fn, err)
|
return nil, fmt.Errorf("updating golden file %v: %v", fn, err)
|
||||||
}
|
}
|
||||||
@ -531,9 +508,3 @@ func TestEvalUnusualFilenames(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func diff(a, b string) string {
|
|
||||||
dmp := diffmatchpatch.New()
|
|
||||||
diffs := dmp.DiffMain(a, b, false)
|
|
||||||
return dmp.DiffPrettyText(diffs)
|
|
||||||
}
|
|
||||||
|
10
testdata/import_syntax_error.golden
vendored
Normal file
10
testdata/import_syntax_error.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
RUNTIME ERROR: testdata/syntax_error.jsonnet:2:1 Unexpected end of file
|
||||||
|
-------------------------------------------------
|
||||||
|
testdata/import_syntax_error:1:1-30 $
|
||||||
|
|
||||||
|
import "syntax_error.jsonnet"
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
During evaluation
|
||||||
|
|
||||||
|
|
1
testdata/import_syntax_error.jsonnet
vendored
Normal file
1
testdata/import_syntax_error.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
import "syntax_error.jsonnet"
|
5
testdata/syntax_error.golden
vendored
Normal file
5
testdata/syntax_error.golden
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
testdata/syntax_error:2:1 Unexpected end of file
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
1
testdata/syntax_error.jsonnet
vendored
Normal file
1
testdata/syntax_error.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
2 +
|
Loading…
x
Reference in New Issue
Block a user