cuelang.org/go@v0.10.1/internal/cuetest/cuetest.go (about) 1 // Copyright 2021 The 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 testing is a helper package for test packages in the CUE project. 16 // As such it should only be imported in _test.go files. 17 package cuetest 18 19 import ( 20 "fmt" 21 "os" 22 "regexp" 23 "testing" 24 25 "cuelang.org/go/internal/tdtest" 26 ) 27 28 const ( 29 envUpdate = "CUE_UPDATE" 30 31 // envNonIssues can be set to a regular expression which indicates what 32 // issues we no longer consider issues, i.e. they should have been fixed. 33 // This should generally result in tests that would otherwise be skipped no 34 // longer being skipped. e.g. CUE_NON_ISSUES=. will cause all issue 35 // tracker conditions (e.g. [golang.org/issues/1234]) to be considered 36 // non-issues. 37 envNonIssues = "CUE_NON_ISSUES" 38 39 envFormatTxtar = "CUE_FORMAT_TXTAR" 40 ) 41 42 var ( 43 // issuesConditions is a set of regular expressions that defines the set of 44 // conditions that can be used to declare links to issues in various issue 45 // trackers. e.g. in testscript condition form 46 // 47 // [golang.org/issues/1234] 48 // [github.com/govim/govim/issues/4321] 49 issuesConditions = []*regexp.Regexp{ 50 regexp.MustCompile(`^golang\.org/issues?/\d+$`), 51 regexp.MustCompile(`^cuelang\.org/issues?/\d+$`), 52 } 53 ) 54 55 // UpdateGoldenFiles determines whether testscript scripts should update txtar 56 // archives in the event of cmp failures. 57 // It is controlled by setting CUE_UPDATE to a non-empty string like "true". 58 // It corresponds to testscript.Params.UpdateGoldenFiles; see its docs for details. 59 var UpdateGoldenFiles = os.Getenv(envUpdate) != "" 60 61 // FormatTxtar ensures that .cue files in txtar test archives are well 62 // formatted, updating the archive as required prior to running a test. 63 // It is controlled by setting CUE_FORMAT_TXTAR to a non-empty string like "true". 64 var FormatTxtar = os.Getenv(envFormatTxtar) != "" 65 66 // Condition adds support for CUE-specific testscript conditions within 67 // testscript scripts. Supported conditions include: 68 // 69 // [golang.org/issue/N] - evaluates to true unless CUE_NON_ISSUES 70 // is set to a regexp that matches the condition, i.e. golang.org/issue/N 71 // in this case 72 // 73 // [cuelang.org/issue/N] - evaluates to true unless CUE_NON_ISSUES 74 // is set to a regexp that matches the condition, i.e. cuelang.org/issue/N 75 // in this case 76 func Condition(cond string) (bool, error) { 77 isIssue, nonIssue, err := checkIssueCondition(cond) 78 if err != nil { 79 return false, err 80 } 81 if isIssue { 82 return !nonIssue, nil 83 } 84 return false, fmt.Errorf("unknown condition %v", cond) 85 } 86 87 // T is an alias to tdtest.T 88 type T = tdtest.T 89 90 func init() { 91 tdtest.UpdateTests = UpdateGoldenFiles 92 } 93 94 // Run creates a new table-driven test using the CUE testing defaults. 95 // 96 // TODO: move this wrapper out to cuetdtest. Users should either use the full 97 // version of tdtest directly, or use the cuetdtest wrapper. 98 func Run[TC any](t *testing.T, table []TC, fn func(t *T, tc *TC)) { 99 tdtest.Run(t, table, fn) 100 } 101 102 // IssueSkip causes the test t to be skipped unless the issue identified 103 // by s is deemed to be a non-issue by CUE_NON_ISSUES. 104 func IssueSkip(t *testing.T, s string) { 105 t.Helper() 106 107 isIssue, nonIssue, err := checkIssueCondition(s) 108 if err != nil { 109 t.Fatal(err) 110 } 111 if !isIssue { 112 t.Fatalf("issue %q does not match a known issue pattern", s) 113 } 114 if nonIssue { 115 t.Skipf("issue %s", s) 116 } 117 } 118 119 // checkIssueCondition examines s to determine whether it is an issue 120 // condition, in which case isIssue is true. If isIssue, then we check 121 // CUE_NON_ISSUES for a match, in which case nonIssue is true (a value of true 122 // indicates roughly that we don't believe issue s is an issue any more). In 123 // case of any errors err is set. 124 func checkIssueCondition(s string) (isIssue bool, nonIssue bool, err error) { 125 var r *regexp.Regexp 126 if v := os.Getenv(envNonIssues); v != "" { 127 r, err = regexp.Compile(v) 128 if err != nil { 129 return false, false, fmt.Errorf("failed to compile regexp %q specified via %v: %v", v, envNonIssues, err) 130 } 131 } 132 for _, c := range issuesConditions { 133 if c.MatchString(s) { 134 isIssue = true 135 } 136 } 137 if !isIssue { 138 return false, false, nil 139 } 140 return isIssue, r != nil && r.MatchString(s), nil 141 }