1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright 2021 The CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package testing is a helper package for test packages in the CUE project.
// As such it should only be imported in _test.go files.
package cuetest
import (
"fmt"
"os"
"regexp"
"testing"
"cuelang.org/go/internal/tdtest"
)
const (
envUpdate = "CUE_UPDATE"
// envNonIssues can be set to a regular expression which indicates what
// issues we no longer consider issues, i.e. they should have been fixed.
// This should generally result in tests that would otherwise be skipped no
// longer being skipped. e.g. CUE_NON_ISSUES=. will cause all issue
// tracker conditions (e.g. [golang.org/issues/1234]) to be considered
// non-issues.
envNonIssues = "CUE_NON_ISSUES"
envFormatTxtar = "CUE_FORMAT_TXTAR"
)
var (
// issuesConditions is a set of regular expressions that defines the set of
// conditions that can be used to declare links to issues in various issue
// trackers. e.g. in testscript condition form
//
// [golang.org/issues/1234]
// [github.com/govim/govim/issues/4321]
issuesConditions = []*regexp.Regexp{
regexp.MustCompile(`^golang\.org/issues?/\d+$`),
regexp.MustCompile(`^cuelang\.org/issues?/\d+$`),
}
)
// UpdateGoldenFiles determines whether tests should update expected
// output in test files in the event of comparison failures (for example
// after a cmp failure in a testscript-based test). It is controlled by
// setting CUE_UPDATE to a non-empty string like "1" or "true". It
// corresponds to testscript.Params.UpdateGoldenFiles; see its docs for
// details.
//
// In some cases, tests might refuse to perform some updates by default.
// The special value "force" can be used to force updates in that situation.
var UpdateGoldenFiles = os.Getenv(envUpdate) != ""
// ForceUpdateGoldenFiles determines whether tests should update
// expected output in test files even when they would not be updated
// usually (for example when there are test regressions).
var ForceUpdateGoldenFiles = os.Getenv(envUpdate) == "force"
// FormatTxtar ensures that .cue files in txtar test archives are well
// formatted, updating the archive as required prior to running a test.
// It is controlled by setting CUE_FORMAT_TXTAR to a non-empty string like "true".
var FormatTxtar = os.Getenv(envFormatTxtar) != ""
// Condition adds support for CUE-specific testscript conditions within
// testscript scripts. Supported conditions include:
//
// [golang.org/issue/N] - evaluates to true unless CUE_NON_ISSUES
// is set to a regexp that matches the condition, i.e. golang.org/issue/N
// in this case
//
// [cuelang.org/issue/N] - evaluates to true unless CUE_NON_ISSUES
// is set to a regexp that matches the condition, i.e. cuelang.org/issue/N
// in this case
func Condition(cond string) (bool, error) {
isIssue, nonIssue, err := checkIssueCondition(cond)
if err != nil {
return false, err
}
if isIssue {
return !nonIssue, nil
}
return false, fmt.Errorf("unknown condition %v", cond)
}
// T is an alias to tdtest.T
type T = tdtest.T
func init() {
tdtest.UpdateTests = UpdateGoldenFiles
}
// Run creates a new table-driven test using the CUE testing defaults.
//
// TODO: move this wrapper out to cuetdtest. Users should either use the full
// version of tdtest directly, or use the cuetdtest wrapper.
func Run[TC any](t *testing.T, table []TC, fn func(t *T, tc *TC)) {
tdtest.Run(t, table, fn)
}
// IssueSkip causes the test t to be skipped unless the issue identified
// by s is deemed to be a non-issue by CUE_NON_ISSUES.
func IssueSkip(t *testing.T, s string) {
t.Helper()
isIssue, nonIssue, err := checkIssueCondition(s)
if err != nil {
t.Fatal(err)
}
if !isIssue {
t.Fatalf("issue %q does not match a known issue pattern", s)
}
if nonIssue {
t.Skipf("issue %s", s)
}
}
// checkIssueCondition examines s to determine whether it is an issue
// condition, in which case isIssue is true. If isIssue, then we check
// CUE_NON_ISSUES for a match, in which case nonIssue is true (a value of true
// indicates roughly that we don't believe issue s is an issue any more). In
// case of any errors err is set.
func checkIssueCondition(s string) (isIssue bool, nonIssue bool, err error) {
var r *regexp.Regexp
if v := os.Getenv(envNonIssues); v != "" {
r, err = regexp.Compile(v)
if err != nil {
return false, false, fmt.Errorf("failed to compile regexp %q specified via %v: %v", v, envNonIssues, err)
}
}
for _, c := range issuesConditions {
if c.MatchString(s) {
isIssue = true
}
}
if !isIssue {
return false, false, nil
}
return isIssue, r != nil && r.MatchString(s), nil
}
|