diff options
author | Tobias Bosch <tbosch@google.com> | 2019-07-08 11:03:26 -0700 |
---|---|---|
committer | Tobias Bosch <tbosch@google.com> | 2019-07-09 08:28:47 +0000 |
commit | 38f3c42a535f0ec2d845c6e299738a4a1996f646 (patch) | |
tree | 7de26451ab815925e2dd8a0da127ab8be5b223a5 /compiler_wrapper/clang_tidy_flag_test.go | |
parent | d868417979bda2479cf8ce0e01768585db2e1f5c (diff) | |
download | toolchain-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.go | 242 |
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) + }) +} |