github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/cmd/tast-lint/internal/check/disallow_testingstate.go (about)

     1  // Copyright 2019 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  package check
     6  
     7  import (
     8  	"go/ast"
     9  	"go/token"
    10  	"strings"
    11  )
    12  
    13  // VerifyTestingStateParam checks if functions in support packages use *testing.State as a parameter.
    14  func VerifyTestingStateParam(fs *token.FileSet, f *ast.File) []*Issue {
    15  	var issues []*Issue
    16  
    17  	// Ignore known valid use cases.
    18  	var allowList = []string{
    19  		// Runs code before and after each local test
    20  		"src/go.chromium.org/tast-tests/cros/local/bundlemain/main.go",
    21  		// Below files are cases still under considering.
    22  		"src/go.chromium.org/tast-tests/cros/local/graphics/trace/trace.go",
    23  	}
    24  	filepath := fs.Position(f.Package).Filename
    25  	for _, p := range allowList {
    26  		if strings.HasSuffix(filepath, p) {
    27  			return issues
    28  		}
    29  	}
    30  
    31  	ast.Inspect(f, func(node ast.Node) bool {
    32  		t := funcType(node)
    33  		if t == nil {
    34  			return true
    35  		}
    36  		for _, param := range t.Params.List {
    37  			if toQualifiedName(removeStars(param.Type)) == "testing.State" {
    38  				issues = append(issues, &Issue{
    39  					Pos:  fs.Position(param.Type.Pos()),
    40  					Msg:  "'testing.State' should not be used in support packages, except for precondition implementation",
    41  					Link: "https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#test-subpackages",
    42  				})
    43  			}
    44  		}
    45  		return true
    46  	})
    47  	return issues
    48  }
    49  
    50  func funcType(node ast.Node) *ast.FuncType {
    51  	if fn, ok := node.(*ast.FuncDecl); ok {
    52  		return fn.Type
    53  	}
    54  	if fn, ok := node.(*ast.FuncLit); ok {
    55  		return fn.Type
    56  	}
    57  	return nil
    58  }
    59  
    60  // VerifyTestingStateStruct checks if testing.State is stored inside struct types.
    61  func VerifyTestingStateStruct(fs *token.FileSet, f *ast.File) []*Issue {
    62  	var issues []*Issue
    63  
    64  	// TODO(crbug.com/1012586): Make below file not use testing.State in struct types.
    65  	var allowList = []string{
    66  		"src/go.chromium.org/tast-tests/cros/local/bundles/cros/platform/memoryuser/mempressure_task.go",
    67  	}
    68  	filepath := fs.Position(f.Package).Filename
    69  	for _, p := range allowList {
    70  		if strings.HasSuffix(filepath, p) {
    71  			return issues
    72  		}
    73  	}
    74  
    75  	ast.Inspect(f, func(node ast.Node) bool {
    76  		st, ok := node.(*ast.StructType)
    77  		if !ok {
    78  			return true
    79  		}
    80  		for _, f := range st.Fields.List {
    81  			if toQualifiedName(removeStars(f.Type)) == "testing.State" {
    82  				issues = append(issues, &Issue{
    83  					Pos:  fs.Position(f.Type.Pos()),
    84  					Msg:  "'testing.State' should not be stored inside a struct type",
    85  					Link: "https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#test-subpackages",
    86  				})
    87  			}
    88  		}
    89  		return true
    90  	})
    91  	return issues
    92  }
    93  
    94  // removeStars returns the exression without stars.
    95  func removeStars(node ast.Expr) ast.Expr {
    96  	star, ok := node.(*ast.StarExpr)
    97  	for ok {
    98  		node = star.X
    99  		star, ok = node.(*ast.StarExpr)
   100  	}
   101  	return node
   102  }