github.com/mcuadros/ascode@v1.3.1/starlark/test/assert.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package test defines utilities for testing Starlark programs. 6 // 7 // Clients can call LoadAssertModule to load a module that defines 8 // several functions useful for testing. See assert.star for its 9 // definition. 10 // 11 // The assert.error function, which reports errors to the current Go 12 // testing.T, requires that clients call SetTest(thread, t) before use. 13 package test 14 15 import ( 16 "fmt" 17 "go/build" 18 "os" 19 "path/filepath" 20 "regexp" 21 "strings" 22 "sync" 23 24 "go.starlark.net/starlark" 25 "go.starlark.net/starlarkstruct" 26 ) 27 28 const localKey = "Reporter" 29 30 // A Reporter is a value to which errors may be reported. 31 // It is satisfied by *testing.T. 32 type Reporter interface { 33 Error(args ...interface{}) 34 } 35 36 // SetReporter associates an error reporter (such as a testing.T in 37 // a Go test) with the Starlark thread so that Starlark programs may 38 // report errors to it. 39 func SetReporter(thread *starlark.Thread, r Reporter) { 40 thread.SetLocal(localKey, r) 41 } 42 43 // GetReporter returns the Starlark thread's error reporter. 44 // It must be preceded by a call to SetReporter. 45 func GetReporter(thread *starlark.Thread) Reporter { 46 r, ok := thread.Local(localKey).(Reporter) 47 if !ok { 48 panic("internal error: starlarktest.SetReporter was not called") 49 } 50 return r 51 } 52 53 var ( 54 once sync.Once 55 assert starlark.StringDict 56 assertErr error 57 ) 58 59 // LoadAssertModule loads the assert module. 60 // It is concurrency-safe and idempotent. 61 func LoadAssertModule() (starlark.StringDict, error) { 62 once.Do(func() { 63 predeclared := starlark.StringDict{ 64 "error": starlark.NewBuiltin("error", errorFn), 65 "catch": starlark.NewBuiltin("catch", catch), 66 "matches": starlark.NewBuiltin("matches", matches), 67 "module": starlark.NewBuiltin("module", starlarkstruct.MakeModule), 68 "_freeze": starlark.NewBuiltin("freeze", freeze), 69 } 70 filename := DataFile("starlark/test", "assert.star") 71 thread := new(starlark.Thread) 72 assert, assertErr = starlark.ExecFile(thread, filename, assertStarFile, predeclared) 73 }) 74 return assert, assertErr 75 } 76 77 // catch(f) evaluates f() and returns its evaluation error message 78 // if it failed or None if it succeeded. 79 func catch(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 80 var fn starlark.Callable 81 if err := starlark.UnpackArgs("catch", args, kwargs, "fn", &fn); err != nil { 82 return nil, err 83 } 84 if _, err := starlark.Call(thread, fn, nil, nil); err != nil { 85 return starlark.String(err.Error()), nil 86 } 87 return starlark.None, nil 88 } 89 90 // matches(pattern, str) reports whether string str matches the regular expression pattern. 91 func matches(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 92 var pattern, str string 93 if err := starlark.UnpackArgs("matches", args, kwargs, "pattern", &pattern, "str", &str); err != nil { 94 return nil, err 95 } 96 ok, err := regexp.MatchString(pattern, str) 97 if err != nil { 98 return nil, fmt.Errorf("matches: %s", err) 99 } 100 return starlark.Bool(ok), nil 101 } 102 103 // error(x) reports an error to the Go test framework. 104 func errorFn(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 105 if len(args) != 1 { 106 return nil, fmt.Errorf("error: got %d arguments, want 1", len(args)) 107 } 108 buf := new(strings.Builder) 109 stk := thread.CallStack() 110 stk.Pop() 111 fmt.Fprintf(buf, "%sError: ", stk) 112 if s, ok := starlark.AsString(args[0]); ok { 113 buf.WriteString(s) 114 } else { 115 buf.WriteString(args[0].String()) 116 } 117 GetReporter(thread).Error(buf.String()) 118 return starlark.None, nil 119 } 120 121 // freeze(x) freezes its operand. 122 func freeze(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 123 if len(kwargs) > 0 { 124 return nil, fmt.Errorf("freeze does not accept keyword arguments") 125 } 126 if len(args) != 1 { 127 return nil, fmt.Errorf("freeze got %d arguments, wants 1", len(args)) 128 } 129 args[0].Freeze() 130 return args[0], nil 131 } 132 133 // DataFile returns the effective filename of the specified 134 // test data resource. The function abstracts differences between 135 // 'go build', under which a test runs in its package directory, 136 // and Blaze, under which a test runs in the root of the tree. 137 var DataFile = func(pkgdir, filename string) string { 138 // Check if we're being run by Bazel and change directories if so. 139 // TEST_SRCDIR and TEST_WORKSPACE are set by the Bazel test runner, so that makes a decent check 140 testSrcdir := os.Getenv("TEST_SRCDIR") 141 testWorkspace := os.Getenv("TEST_WORKSPACE") 142 if testSrcdir != "" && testWorkspace != "" { 143 return filepath.Join(testSrcdir, "net_starlark_go", pkgdir, filename) 144 } 145 146 return filepath.Join(build.Default.GOPATH, "src/github.com/mcuadros/ascode", pkgdir, filename) 147 }