aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/clang_tidy_flag_test.go
diff options
context:
space:
mode:
authorTobias Bosch <tbosch@google.com>2019-07-08 11:03:26 -0700
committerTobias Bosch <tbosch@google.com>2019-07-09 08:28:47 +0000
commit38f3c42a535f0ec2d845c6e299738a4a1996f646 (patch)
tree7de26451ab815925e2dd8a0da127ab8be5b223a5 /compiler_wrapper/clang_tidy_flag_test.go
parentd868417979bda2479cf8ce0e01768585db2e1f5c (diff)
downloadtoolchain-utils-38f3c42a535f0ec2d845c6e299738a4a1996f646.tar.gz
Support calling clang-tidy in the compiler wrapper.
BUG=chromium:773875 TEST=unit test Change-Id: Iba2a8c38c5542b6289373e8c8e97e2e671008aef Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1691114 Reviewed-by: Tobias Bosch <tbosch@google.com> Tested-by: Tobias Bosch <tbosch@google.com>
Diffstat (limited to 'compiler_wrapper/clang_tidy_flag_test.go')
-rw-r--r--compiler_wrapper/clang_tidy_flag_test.go242
1 files changed, 242 insertions, 0 deletions
diff --git a/compiler_wrapper/clang_tidy_flag_test.go b/compiler_wrapper/clang_tidy_flag_test.go
new file mode 100644
index 00000000..5fc29318
--- /dev/null
+++ b/compiler_wrapper/clang_tidy_flag_test.go
@@ -0,0 +1,242 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+ "testing"
+)
+
+func TestClangTidyBasename(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ testData := []struct {
+ in string
+ out string
+ }{
+ {"./x86_64-cros-linux-gnu-clang", ".*/clang-tidy"},
+ {"./x86_64-cros-linux-gnu-clang++", ".*/clang-tidy"},
+ }
+
+ var clangTidyCmd *command
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ if ctx.cmdCount == 2 {
+ clangTidyCmd = cmd
+ }
+ return nil
+ }
+
+ for _, tt := range testData {
+ ctx.cmdCount = 0
+ clangTidyCmd = nil
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(tt.in, mainCc)))
+ if ctx.cmdCount != 3 {
+ t.Errorf("expected 3 calls. Got: %d", ctx.cmdCount)
+ }
+ if err := verifyPath(clangTidyCmd, tt.out); err != nil {
+ t.Error(err)
+ }
+ }
+ })
+}
+
+func TestClangTidyClangResourceDir(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ if err := verifyPath(cmd, "usr/bin/clang"); err != nil {
+ t.Error(err)
+ }
+ if err := verifyArgOrder(cmd, "--print-resource-dir"); err != nil {
+ t.Error(err)
+ }
+ fmt.Fprint(stdout, "someResourcePath")
+ return nil
+ case 2:
+ if err := verifyPath(cmd, "usr/bin/clang-tidy"); err != nil {
+ return err
+ }
+ if err := verifyArgOrder(cmd, "-resource-dir=someResourcePath", mainCc); err != nil {
+ return err
+ }
+ return nil
+ case 3:
+ if err := verifyPath(cmd, "usr/bin/clang"); err != nil {
+ t.Error(err)
+ }
+ return nil
+ default:
+ t.Fatalf("unexpected command %#v", cmd)
+ return nil
+ }
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc)))
+ if ctx.cmdCount != 3 {
+ t.Errorf("expected 3 calls. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestClangTidyArgOrder(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ if ctx.cmdCount == 2 {
+ if err := verifyArgOrder(cmd, "-checks=.*", mainCc, "--", "-resource-dir=.*", mainCc, "--some_arg"); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc, "--some_arg")))
+ if ctx.cmdCount != 3 {
+ t.Errorf("expected 3 calls. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestForwardStdOutAndStderrFromClangTidyCall(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ if ctx.cmdCount == 2 {
+ fmt.Fprintf(stdout, "somemessage")
+ fmt.Fprintf(stderr, "someerror")
+ }
+ return nil
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc)))
+ if ctx.stdoutString() != "somemessage" {
+ t.Errorf("stdout was not forwarded. Got: %s", ctx.stdoutString())
+ }
+ if ctx.stderrString() != "someerror" {
+ t.Errorf("stderr was not forwarded. Got: %s", ctx.stderrString())
+ }
+ })
+}
+
+func TestIgnoreNonZeroExitCodeFromClangTidy(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ if ctx.cmdCount == 2 {
+ return newExitCodeError(23)
+ }
+ return nil
+ }
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc)))
+ stderr := ctx.stderrString()
+ if err := verifyNonInternalError(stderr, "clang-tidy failed"); err != nil {
+ t.Error(err)
+ }
+ })
+}
+
+func TestReportGeneralErrorsFromClangTidy(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ if ctx.cmdCount == 2 {
+ return errors.New("someerror")
+ }
+ return nil
+ }
+ stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc)))
+ if err := verifyInternalError(stderr); err != nil {
+ t.Fatal(err)
+ }
+ if !strings.Contains(stderr, "someerror") {
+ t.Errorf("unexpected error. Got: %s", stderr)
+ }
+ })
+}
+
+func TestOmitClangTidyForGcc(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(gccX86_64, mainCc)))
+ if ctx.cmdCount > 1 {
+ t.Errorf("expected 1 command. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestOmitClangTidyForGccWithClangSyntax(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(gccX86_64, "-clang-syntax", mainCc)))
+ if ctx.cmdCount > 2 {
+ t.Errorf("expected 2 commands. Got: %d", ctx.cmdCount)
+ }
+ })
+}
+
+func TestUseClangTidyBasedOnFileExtension(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ testData := []struct {
+ args []string
+ clangTidy bool
+ }{
+ {[]string{"main.cc"}, true},
+ {[]string{"main.cc"}, true},
+ {[]string{"main.C"}, true},
+ {[]string{"main.cxx"}, true},
+ {[]string{"main.c++"}, true},
+ {[]string{"main.xy"}, false},
+ {[]string{"-o", "main.cc"}, false},
+ {[]string{}, false},
+ }
+ for _, tt := range testData {
+ ctx.cmdCount = 0
+ ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, tt.args...)))
+ if ctx.cmdCount > 1 && !tt.clangTidy {
+ t.Errorf("expected a call to clang tidy but got none for args %s", tt.args)
+ }
+ if ctx.cmdCount == 1 && tt.clangTidy {
+ t.Errorf("expected no call to clang tidy but got one for args %s", tt.args)
+ }
+ }
+ })
+}
+
+func TestOmitCCacheWithClangTidy(t *testing.T) {
+ withClangSyntaxTestContext(t, func(ctx *testContext) {
+ ctx.cfg.useCCache = true
+
+ ctx.cmdMock = func(cmd *command, stdout io.Writer, stderr io.Writer) error {
+ switch ctx.cmdCount {
+ case 1:
+ if err := verifyPath(cmd, "usr/bin/clang"); err != nil {
+ t.Error(err)
+ }
+ return nil
+ case 2:
+ if err := verifyPath(cmd, "usr/bin/clang-tidy"); err != nil {
+ return err
+ }
+ return nil
+ default:
+ return nil
+ }
+ }
+ cmd := ctx.must(callCompiler(ctx, ctx.cfg,
+ ctx.newCommand(clangX86_64, mainCc)))
+ if ctx.cmdCount != 3 {
+ t.Errorf("expected 3 calls. Got: %d", ctx.cmdCount)
+ }
+ if err := verifyPath(cmd, "usr/bin/clang"); err != nil {
+ t.Error(err)
+ }
+ })
+}
+
+func withClangSyntaxTestContext(t *testing.T, work func(ctx *testContext)) {
+ withTestContext(t, func(ctx *testContext) {
+ ctx.env = []string{"WITH_TIDY=1"}
+ work(ctx)
+ })
+}