github.com/0xKiwi/rules_go@v0.24.3/tests/core/nogo/vet/vet_test.go (about)

     1  // Copyright 2019 The Bazel Authors. All rights reserved.
     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 vet_test
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"regexp"
    22  	"testing"
    23  
    24  	"github.com/bazelbuild/rules_go/go/tools/bazel_testing"
    25  )
    26  
    27  func TestMain(m *testing.M) {
    28  	bazel_testing.TestMain(m, bazel_testing.Args{
    29  		Main: `
    30  -- BUILD.bazel --
    31  load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_tool_library", "nogo")
    32  
    33  nogo(
    34      name = "nogo",
    35      vet = True,
    36      visibility = ["//visibility:public"],
    37  )
    38  
    39  go_library(
    40      name = "has_errors",
    41      srcs = ["has_errors.go"],
    42      importpath = "haserrors",
    43      deps = [":fmtwrap"],
    44  )
    45  
    46  go_library(
    47      name = "no_errors",
    48      srcs = ["no_errors.go"],
    49      cgo = True,
    50      importpath = "noerrors",
    51  )
    52  
    53  go_library(
    54      name = "fmtwrap",
    55      srcs = ["fmtwrap.go"],
    56      importpath = "fmtwrap",
    57  )
    58  
    59  -- has_errors.go --
    60  package haserrors
    61  
    62  // +build build_tags_error
    63  
    64  import (
    65  	"fmtwrap"
    66  	"sync/atomic"
    67  )
    68  
    69  func F() {}
    70  
    71  func Foo() bool {
    72  	x := uint64(1)
    73  	_ = atomic.AddUint64(&x, 1)
    74  	if F == nil { // nilfunc error.
    75  		return false
    76  	}
    77  	fmtwrap.Printf("%b", "hi") // printf error.
    78  	return true || true        // redundant boolean error.
    79  }
    80  
    81  -- no_errors.go --
    82  package noerrors
    83  
    84  // const int x = 1;
    85  import "C"
    86  
    87  func Foo() bool {
    88  	return bool(C.x == 1)
    89  }
    90  
    91  -- fmtwrap.go --
    92  package fmtwrap
    93  
    94  import "fmt"
    95  
    96  func Printf(format string, args ...interface{}) {
    97  	fmt.Printf(format, args...)
    98  }
    99  `,
   100  	})
   101  }
   102  
   103  func Test(t *testing.T) {
   104  	for _, test := range []struct {
   105  		desc, nogo, target string
   106  		wantSuccess        bool
   107  		includes, excludes []string
   108  	}{
   109  		{
   110  			desc:        "default",
   111  			target:      "//:has_errors",
   112  			wantSuccess: true,
   113  			excludes: []string{
   114  				"\\+build comment must appear before package clause and be followed by a blank line",
   115  				"comparison of function F == nil is always false",
   116  				"Printf format %b has arg \"hi\" of wrong type string",
   117  				"redundant or: true \\|\\| true",
   118  			},
   119  		}, {
   120  			desc:        "enabled_no_errors",
   121  			target:      "//:no_errors",
   122  			wantSuccess: true,
   123  		}, {
   124  			desc:   "enabled_has_errors",
   125  			nogo:   "@//:nogo",
   126  			target: "//:has_errors",
   127  			includes: []string{
   128  				"\\+build comment must appear before package clause and be followed by a blank line",
   129  				"comparison of function F == nil is always false",
   130  				"Printf format %b has arg \"hi\" of wrong type string",
   131  				"redundant or: true \\|\\| true",
   132  			},
   133  		},
   134  	} {
   135  		t.Run(test.desc, func(t *testing.T) {
   136  			if test.nogo != "" {
   137  				origRegister := "go_register_toolchains()"
   138  				customRegister := fmt.Sprintf("go_register_toolchains(nogo = %q)", test.nogo)
   139  				if err := replaceInFile("WORKSPACE", origRegister, customRegister); err != nil {
   140  					t.Fatal(err)
   141  				}
   142  				defer replaceInFile("WORKSPACE", customRegister, origRegister)
   143  			}
   144  
   145  			cmd := bazel_testing.BazelCmd("build", test.target)
   146  			stderr := &bytes.Buffer{}
   147  			cmd.Stderr = stderr
   148  			if err := cmd.Run(); err == nil && !test.wantSuccess {
   149  				t.Fatal("unexpected success")
   150  			} else if err != nil && test.wantSuccess {
   151  				t.Fatalf("unexpected error: %v", err)
   152  			}
   153  
   154  			for _, pattern := range test.includes {
   155  				if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
   156  					t.Fatal(err)
   157  				} else if !matched {
   158  					t.Errorf("output did not contain pattern: %s", pattern)
   159  				}
   160  			}
   161  			for _, pattern := range test.excludes {
   162  				if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil {
   163  					t.Fatal(err)
   164  				} else if matched {
   165  					t.Errorf("output contained pattern: %s", pattern)
   166  				}
   167  			}
   168  		})
   169  	}
   170  }
   171  
   172  func replaceInFile(path, old, new string) error {
   173  	data, err := ioutil.ReadFile(path)
   174  	if err != nil {
   175  		return err
   176  	}
   177  	data = bytes.ReplaceAll(data, []byte(old), []byte(new))
   178  	return ioutil.WriteFile(path, data, 0666)
   179  }