| // Copyright 2019 The Bazel Authors. All rights reserved. |
| // |
| // 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 vet_test |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io/ioutil" |
| "regexp" |
| "testing" |
| |
| "github.com/bazelbuild/rules_go/go/tools/bazel_testing" |
| ) |
| |
| func TestMain(m *testing.M) { |
| bazel_testing.TestMain(m, bazel_testing.Args{ |
| Main: ` |
| -- BUILD.bazel -- |
| load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_tool_library", "nogo") |
| |
| nogo( |
| name = "nogo", |
| vet = True, |
| visibility = ["//visibility:public"], |
| ) |
| |
| go_library( |
| name = "has_errors", |
| srcs = ["has_errors.go"], |
| importpath = "haserrors", |
| deps = [":fmtwrap"], |
| ) |
| |
| go_library( |
| name = "no_errors", |
| srcs = ["no_errors.go"], |
| cgo = True, |
| importpath = "noerrors", |
| ) |
| |
| go_library( |
| name = "fmtwrap", |
| srcs = ["fmtwrap.go"], |
| importpath = "fmtwrap", |
| ) |
| |
| -- has_errors.go -- |
| package haserrors |
| |
| // +build build_tags_error |
| |
| import ( |
| "fmtwrap" |
| "sync/atomic" |
| ) |
| |
| func F() {} |
| |
| func Foo() bool { |
| x := uint64(1) |
| _ = atomic.AddUint64(&x, 1) |
| if F == nil { // nilfunc error. |
| return false |
| } |
| fmtwrap.Printf("%b", "hi") // printf error. |
| return true || true // redundant boolean error. |
| } |
| |
| -- no_errors.go -- |
| package noerrors |
| |
| // const int x = 1; |
| import "C" |
| |
| func Foo() bool { |
| return bool(C.x == 1) |
| } |
| |
| -- fmtwrap.go -- |
| package fmtwrap |
| |
| import "fmt" |
| |
| func Printf(format string, args ...interface{}) { |
| fmt.Printf(format, args...) |
| } |
| `, |
| }) |
| } |
| |
| func Test(t *testing.T) { |
| for _, test := range []struct { |
| desc, nogo, target string |
| wantSuccess bool |
| includes, excludes []string |
| }{ |
| { |
| desc: "default", |
| target: "//:has_errors", |
| wantSuccess: true, |
| excludes: []string{ |
| "\\+build comment must appear before package clause and be followed by a blank line", |
| "comparison of function F == nil is always false", |
| "Printf format %b has arg \"hi\" of wrong type string", |
| "redundant or: true \\|\\| true", |
| }, |
| }, { |
| desc: "enabled_no_errors", |
| target: "//:no_errors", |
| wantSuccess: true, |
| }, { |
| desc: "enabled_has_errors", |
| nogo: "@//:nogo", |
| target: "//:has_errors", |
| includes: []string{ |
| "\\+build comment must appear before package clause and be followed by a blank line", |
| "comparison of function F == nil is always false", |
| "Printf format %b has arg \"hi\" of wrong type string", |
| "redundant or: true \\|\\| true", |
| }, |
| }, |
| } { |
| t.Run(test.desc, func(t *testing.T) { |
| if test.nogo != "" { |
| origRegister := "go_register_toolchains()" |
| customRegister := fmt.Sprintf("go_register_toolchains(nogo = %q)", test.nogo) |
| if err := replaceInFile("WORKSPACE", origRegister, customRegister); err != nil { |
| t.Fatal(err) |
| } |
| defer replaceInFile("WORKSPACE", customRegister, origRegister) |
| } |
| |
| cmd := bazel_testing.BazelCmd("build", test.target) |
| stderr := &bytes.Buffer{} |
| cmd.Stderr = stderr |
| if err := cmd.Run(); err == nil && !test.wantSuccess { |
| t.Fatal("unexpected success") |
| } else if err != nil && test.wantSuccess { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| |
| for _, pattern := range test.includes { |
| if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil { |
| t.Fatal(err) |
| } else if !matched { |
| t.Errorf("output did not contain pattern: %s", pattern) |
| } |
| } |
| for _, pattern := range test.excludes { |
| if matched, err := regexp.Match(pattern, stderr.Bytes()); err != nil { |
| t.Fatal(err) |
| } else if matched { |
| t.Errorf("output contained pattern: %s", pattern) |
| } |
| } |
| }) |
| } |
| } |
| |
| func replaceInFile(path, old, new string) error { |
| data, err := ioutil.ReadFile(path) |
| if err != nil { |
| return err |
| } |
| data = bytes.ReplaceAll(data, []byte(old), []byte(new)) |
| return ioutil.WriteFile(path, data, 0666) |
| } |