github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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  
    26  const (
    27  	// envUpdate is used in the definition of UpdateGoldenFiles
    28  	envUpdate = "CUE_UPDATE"
    29  
    30  	// envNonIssues can be set to a regular expression which indicates what
    31  	// issues we no longer consider issues, i.e. they should have been fixed.
    32  	// This should generally result in tests that would otherwise be skipped no
    33  	// longer being skipped.  e.g.  CUE_NON_ISSUES=. will cause all issue
    34  	// tracker conditions (e.g. [golang.org/issues/1234]) to be considered
    35  	// non-issues.
    36  	envNonIssues = "CUE_NON_ISSUES"
    37  
    38  	envFormatTxtar = "CUE_FORMAT_TXTAR"
    39  )
    40  
    41  var (
    42  	// issuesConditions is a set of regular expressions that defines the set of
    43  	// conditions that can be used to declare links to issues in various issue
    44  	// trackers. e.g. in testscript condition form
    45  	//
    46  	//     [golang.org/issues/1234]
    47  	//     [github.com/govim/govim/issues/4321]
    48  	issuesConditions = []*regexp.Regexp{
    49  		regexp.MustCompile(`^golang\.org/issues?/\d+$`),
    50  		regexp.MustCompile(`^cuelang\.org/issues?/\d+$`),
    51  	}
    52  )
    53  
    54  // UpdateGoldenFiles determines whether testscript scripts should update txtar
    55  // archives in the event of cmp failures. It corresponds to
    56  // testscript.Params.UpdateGoldenFiles. See the docs for
    57  // testscript.Params.UpdateGoldenFiles for more details.
    58  var UpdateGoldenFiles = os.Getenv(envUpdate) != ""
    59  
    60  // FormatTxtar ensures that .cue files in txtar test archives are well
    61  // formatted, updating the archive as required prior to running a test.
    62  var FormatTxtar = os.Getenv(envFormatTxtar) != ""
    63  
    64  // Condition adds support for CUE-specific testscript conditions within
    65  // testscript scripts. Supported conditions include:
    66  //
    67  // [long] - evalutates to true when the long build tag is specified
    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  //
    77  func Condition(cond string) (bool, error) {
    78  	isIssue, nonIssue, err := checkIssueCondition(cond)
    79  	if err != nil {
    80  		return false, err
    81  	}
    82  	if isIssue {
    83  		return !nonIssue, nil
    84  	}
    85  	switch cond {
    86  	case "long":
    87  		return Long, nil
    88  	}
    89  	return false, fmt.Errorf("unknown condition %v", cond)
    90  }
    91  
    92  // IssueSkip causes the test t to be skipped unless the issue identified
    93  // by s is deemed to be a non-issue by CUE_NON_ISSUES.
    94  func IssueSkip(t *testing.T, s string) {
    95  	isIssue, nonIssue, err := checkIssueCondition(s)
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  	if !isIssue {
   100  		t.Fatalf("issue %q does not match a known issue pattern", s)
   101  	}
   102  	if nonIssue {
   103  		t.Skipf("issue %s", s)
   104  	}
   105  }
   106  
   107  // checkIssueCondition examines s to determine whether it is an issue
   108  // condition, in which case isIssue is true. If isIssue, then we check
   109  // CUE_NON_ISSUES for a match, in which case nonIssue is true (a value of true
   110  // indicates roughly that we don't believe issue s is an issue any more). In
   111  // case of any errors err is set.
   112  func checkIssueCondition(s string) (isIssue bool, nonIssue bool, err error) {
   113  	var r *regexp.Regexp
   114  	if v := os.Getenv(envNonIssues); v != "" {
   115  		r, err = regexp.Compile(v)
   116  		if err != nil {
   117  			return false, false, fmt.Errorf("failed to compile regexp %q specified via %v: %v", v, envNonIssues, err)
   118  		}
   119  	}
   120  	for _, c := range issuesConditions {
   121  		if c.MatchString(s) {
   122  			isIssue = true
   123  		}
   124  	}
   125  	if !isIssue {
   126  		return false, false, nil
   127  	}
   128  	return isIssue, r != nil && r.MatchString(s), nil
   129  }