1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors 2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be 3*760c253cSXin Li// found in the LICENSE file. 4*760c253cSXin Li 5*760c253cSXin Lipackage main 6*760c253cSXin Li 7*760c253cSXin Liimport ( 8*760c253cSXin Li "errors" 9*760c253cSXin Li "fmt" 10*760c253cSXin Li "io" 11*760c253cSXin Li "path/filepath" 12*760c253cSXin Li "strings" 13*760c253cSXin Li "testing" 14*760c253cSXin Li) 15*760c253cSXin Li 16*760c253cSXin Lifunc TestClangBasename(t *testing.T) { 17*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 18*760c253cSXin Li var tests = []struct { 19*760c253cSXin Li in string 20*760c253cSXin Li out string 21*760c253cSXin Li }{ 22*760c253cSXin Li {"./x86_64-cros-linux-gnu-clang", ".*/clang"}, 23*760c253cSXin Li {"./x86_64-cros-linux-gnu-clang++", ".*/clang\\+\\+"}, 24*760c253cSXin Li } 25*760c253cSXin Li 26*760c253cSXin Li for _, tt := range tests { 27*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 28*760c253cSXin Li ctx.newCommand(tt.in, mainCc))) 29*760c253cSXin Li if err := verifyPath(cmd, tt.out); err != nil { 30*760c253cSXin Li t.Error(err) 31*760c253cSXin Li } 32*760c253cSXin Li } 33*760c253cSXin Li }) 34*760c253cSXin Li} 35*760c253cSXin Li 36*760c253cSXin Lifunc TestClangPathGivenClangEnv(t *testing.T) { 37*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 38*760c253cSXin Li ctx.env = []string{"CLANG=/a/b/clang"} 39*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 40*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 41*760c253cSXin Li if err := verifyPath(cmd, "/a/b/clang"); err != nil { 42*760c253cSXin Li t.Error(err) 43*760c253cSXin Li } 44*760c253cSXin Li }) 45*760c253cSXin Li} 46*760c253cSXin Li 47*760c253cSXin Lifunc TestAbsoluteClangPathBasedOnRootPath(t *testing.T) { 48*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 49*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 50*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 51*760c253cSXin Li ctx.newCommand(filepath.Join(ctx.tempDir, clangX86_64), mainCc))) 52*760c253cSXin Li if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "somepath/usr/bin/clang")); err != nil { 53*760c253cSXin Li t.Error(err) 54*760c253cSXin Li } 55*760c253cSXin Li }) 56*760c253cSXin Li} 57*760c253cSXin Li 58*760c253cSXin Lifunc TestRelativeClangPathBasedOnRootPath(t *testing.T) { 59*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 60*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 61*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 62*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 63*760c253cSXin Li if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil { 64*760c253cSXin Li t.Error(err) 65*760c253cSXin Li } 66*760c253cSXin Li }) 67*760c253cSXin Li} 68*760c253cSXin Li 69*760c253cSXin Lifunc TestRelativeClangPathWithDirBasedOnRootPath(t *testing.T) { 70*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 71*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 72*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 73*760c253cSXin Li ctx.newCommand("test/x86_64-cros-linux-gnu-clang", mainCc))) 74*760c253cSXin Li if err := verifyPath(cmd, "test/somepath/usr/bin/clang"); err != nil { 75*760c253cSXin Li t.Error(err) 76*760c253cSXin Li } 77*760c253cSXin Li }) 78*760c253cSXin Li} 79*760c253cSXin Li 80*760c253cSXin Lifunc TestPathEnvClangPathBasedOnRootPath(t *testing.T) { 81*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 82*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 83*760c253cSXin Li ctx.env = []string{"PATH=" + filepath.Join(ctx.tempDir, "/pathenv")} 84*760c253cSXin Li ctx.writeFile(filepath.Join(ctx.tempDir, "/pathenv/x86_64-cros-linux-gnu-clang"), "") 85*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 86*760c253cSXin Li ctx.newCommand("x86_64-cros-linux-gnu-clang", mainCc))) 87*760c253cSXin Li if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "pathenv/somepath/usr/bin/clang")); err != nil { 88*760c253cSXin Li t.Error(err) 89*760c253cSXin Li } 90*760c253cSXin Li }) 91*760c253cSXin Li} 92*760c253cSXin Li 93*760c253cSXin Lifunc TestClangPathForClangHostWrapper(t *testing.T) { 94*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 95*760c253cSXin Li ctx.cfg.isHostWrapper = true 96*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 97*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 98*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 99*760c253cSXin Li if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "clang")); err != nil { 100*760c253cSXin Li t.Error(err) 101*760c253cSXin Li } 102*760c253cSXin Li }) 103*760c253cSXin Li} 104*760c253cSXin Li 105*760c253cSXin Lifunc TestClangPathForAndroidWrapper(t *testing.T) { 106*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 107*760c253cSXin Li ctx.cfg.isAndroidWrapper = true 108*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 109*760c253cSXin Li ctx.newCommand("somedir/clang", mainCc))) 110*760c253cSXin Li if err := verifyPath(cmd, "somedir/clang.real"); err != nil { 111*760c253cSXin Li t.Error(err) 112*760c253cSXin Li } 113*760c253cSXin Li }) 114*760c253cSXin Li} 115*760c253cSXin Li 116*760c253cSXin Lifunc TestClangPathForAndroidWrapperWithSymlinks(t *testing.T) { 117*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 118*760c253cSXin Li ctx.cfg.isAndroidWrapper = true 119*760c253cSXin Li ctx.writeFile("base/come_clang", "") 120*760c253cSXin Li ctx.symlink("base/some_clang", "linked/clang") 121*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 122*760c253cSXin Li ctx.newCommand("linked/clang", mainCc))) 123*760c253cSXin Li if err := verifyPath(cmd, "linked/some_clang.real"); err != nil { 124*760c253cSXin Li t.Error(err) 125*760c253cSXin Li } 126*760c253cSXin Li }) 127*760c253cSXin Li} 128*760c253cSXin Li 129*760c253cSXin Lifunc TestUseXclangPathAndCalcResourceDirByNestedClangCall(t *testing.T) { 130*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 131*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 132*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 133*760c253cSXin Li if ctx.cmdCount > 1 { 134*760c253cSXin Li return nil 135*760c253cSXin Li } 136*760c253cSXin Li if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil { 137*760c253cSXin Li t.Error(err) 138*760c253cSXin Li } 139*760c253cSXin Li if err := verifyArgOrder(cmd, "--print-resource-dir"); err != nil { 140*760c253cSXin Li t.Error(err) 141*760c253cSXin Li } 142*760c253cSXin Li fmt.Fprint(stdout, "someResourcePath\n") 143*760c253cSXin Li return nil 144*760c253cSXin Li } 145*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 146*760c253cSXin Li ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc))) 147*760c253cSXin Li if err := verifyPath(cmd, "somedir/clang"); err != nil { 148*760c253cSXin Li t.Error(err) 149*760c253cSXin Li } 150*760c253cSXin Li if err := verifyArgOrder(cmd, "-resource-dir=someResourcePath", 151*760c253cSXin Li "--gcc-toolchain=/usr", mainCc); err != nil { 152*760c253cSXin Li t.Error(err) 153*760c253cSXin Li } 154*760c253cSXin Li }) 155*760c253cSXin Li} 156*760c253cSXin Li 157*760c253cSXin Lifunc TestXclangPathFailIfNestedClangCallFails(t *testing.T) { 158*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 159*760c253cSXin Li ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 160*760c253cSXin Li fmt.Fprint(stderr, "someclangerror") 161*760c253cSXin Li return errors.New("someerror") 162*760c253cSXin Li } 163*760c253cSXin Li stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 164*760c253cSXin Li ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc))) 165*760c253cSXin Li if err := verifyInternalError(stderr); err != nil { 166*760c253cSXin Li t.Fatal(err) 167*760c253cSXin Li } 168*760c253cSXin Li if !strings.Contains(stderr, "clang") { 169*760c253cSXin Li t.Errorf("could not find compiler path on stderr. Got: %s", stderr) 170*760c253cSXin Li } 171*760c253cSXin Li if !strings.Contains(stderr, "someerror") { 172*760c253cSXin Li t.Errorf("could not find original error on stderr. Got: %s", stderr) 173*760c253cSXin Li } 174*760c253cSXin Li if !strings.Contains(stderr, "someclangerror") { 175*760c253cSXin Li t.Errorf("stderr was not forwarded. Got: %s", stderr) 176*760c253cSXin Li } 177*760c253cSXin Li }) 178*760c253cSXin Li} 179*760c253cSXin Li 180*760c253cSXin Lifunc TestConvertGccToClangFlags(t *testing.T) { 181*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 182*760c253cSXin Li var tests = []struct { 183*760c253cSXin Li in string 184*760c253cSXin Li out string 185*760c253cSXin Li }{ 186*760c253cSXin Li {"-Wno-error=maybe-uninitialized", "-Wno-error=uninitialized"}, 187*760c253cSXin Li {"-Wno-error=cpp", "-Wno-#warnings"}, 188*760c253cSXin Li {"-Xclang-only=-abc=xyz", "-abc=xyz"}, 189*760c253cSXin Li } 190*760c253cSXin Li 191*760c253cSXin Li for _, tt := range tests { 192*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 193*760c253cSXin Li ctx.newCommand(clangX86_64, tt.in, mainCc))) 194*760c253cSXin Li if err := verifyArgCount(cmd, 0, tt.in); err != nil { 195*760c253cSXin Li t.Error(err) 196*760c253cSXin Li } 197*760c253cSXin Li if err := verifyArgOrder(cmd, tt.out, mainCc); err != nil { 198*760c253cSXin Li t.Error(err) 199*760c253cSXin Li } 200*760c253cSXin Li } 201*760c253cSXin Li }) 202*760c253cSXin Li} 203*760c253cSXin Li 204*760c253cSXin Lifunc TestFilterUnsupportedClangFlags(t *testing.T) { 205*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 206*760c253cSXin Li var tests = []struct { 207*760c253cSXin Li compiler string 208*760c253cSXin Li flag string 209*760c253cSXin Li expectedCount int 210*760c253cSXin Li }{ 211*760c253cSXin Li {clangX86_64, "-Wstrict-aliasing=xyz", 0}, 212*760c253cSXin Li {clangX86_64, "-finline-limit=xyz", 0}, 213*760c253cSXin Li {"./armv7a-cros-linux-gnu-clang", "-ftrapv", 0}, 214*760c253cSXin Li {"./armv7a-cros-win-gnu-clang", "-ftrapv", 1}, 215*760c253cSXin Li {"./armv8a-cros-win-gnu-clang", "-ftrapv", 1}, 216*760c253cSXin Li {clangX86_64, "-ftrapv", 1}, 217*760c253cSXin Li } 218*760c253cSXin Li 219*760c253cSXin Li for _, tt := range tests { 220*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 221*760c253cSXin Li ctx.newCommand(tt.compiler, tt.flag, mainCc))) 222*760c253cSXin Li if err := verifyArgCount(cmd, tt.expectedCount, tt.flag); err != nil { 223*760c253cSXin Li t.Error(err) 224*760c253cSXin Li } 225*760c253cSXin Li } 226*760c253cSXin Li }) 227*760c253cSXin Li} 228*760c253cSXin Li 229*760c253cSXin Lifunc TestClangArchFlags(t *testing.T) { 230*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 231*760c253cSXin Li var tests = []struct { 232*760c253cSXin Li compiler string 233*760c253cSXin Li flags []string 234*760c253cSXin Li }{ 235*760c253cSXin Li {"./i686_64-cros-linux-gnu-clang", []string{mainCc, "-target", "i686_64-cros-linux-gnu"}}, 236*760c253cSXin Li {"./x86_64-cros-linux-gnu-clang", []string{mainCc, "-target", "x86_64-cros-linux-gnu"}}, 237*760c253cSXin Li } 238*760c253cSXin Li for _, tt := range tests { 239*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 240*760c253cSXin Li ctx.newCommand(tt.compiler, mainCc))) 241*760c253cSXin Li if err := verifyArgOrder(cmd, tt.flags...); err != nil { 242*760c253cSXin Li t.Error(err) 243*760c253cSXin Li } 244*760c253cSXin Li } 245*760c253cSXin Li }) 246*760c253cSXin Li} 247*760c253cSXin Li 248*760c253cSXin Lifunc TestClangLinkerPathProbesBinariesOnPath(t *testing.T) { 249*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 250*760c253cSXin Li linkerPath := filepath.Join(ctx.tempDir, "a/b/c") 251*760c253cSXin Li ctx.writeFile(filepath.Join(linkerPath, "x86_64-cros-linux-gnu-ld.bfd"), "") 252*760c253cSXin Li ctx.env = []string{"PATH=nonExistantPath:" + linkerPath} 253*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 254*760c253cSXin Li ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc))) 255*760c253cSXin Li if err := verifyArgOrder(cmd, "-Ba/b/c"); err != nil { 256*760c253cSXin Li t.Error(err) 257*760c253cSXin Li } 258*760c253cSXin Li if err := verifyArgOrder(cmd, "--prefix=a/b/c/x86_64-cros-linux-gnu-"); err != nil { 259*760c253cSXin Li t.Error(err) 260*760c253cSXin Li } 261*760c253cSXin Li 262*760c253cSXin Li }) 263*760c253cSXin Li} 264*760c253cSXin Li 265*760c253cSXin Lifunc TestClangLinkerPathEvaluatesSymlinksForBinariesOnPath(t *testing.T) { 266*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 267*760c253cSXin Li realLinkerPath := filepath.Join(ctx.tempDir, "a/original/path/somelinker") 268*760c253cSXin Li ctx.writeFile(realLinkerPath, "") 269*760c253cSXin Li firstLinkLinkerPath := filepath.Join(ctx.tempDir, "a/first/somelinker") 270*760c253cSXin Li ctx.symlink(realLinkerPath, firstLinkLinkerPath) 271*760c253cSXin Li secondLinkLinkerPath := filepath.Join(ctx.tempDir, "a/second/x86_64-cros-linux-gnu-ld.bfd") 272*760c253cSXin Li ctx.symlink(firstLinkLinkerPath, secondLinkLinkerPath) 273*760c253cSXin Li 274*760c253cSXin Li ctx.env = []string{"PATH=nonExistantPath:" + filepath.Dir(secondLinkLinkerPath)} 275*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 276*760c253cSXin Li ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc))) 277*760c253cSXin Li if err := verifyArgOrder(cmd, "-Ba/first"); err != nil { 278*760c253cSXin Li t.Error(err) 279*760c253cSXin Li } 280*760c253cSXin Li if err := verifyArgOrder(cmd, "--prefix=a/first/x86_64-cros-linux-gnu-"); err != nil { 281*760c253cSXin Li t.Error(err) 282*760c253cSXin Li } 283*760c253cSXin Li 284*760c253cSXin Li }) 285*760c253cSXin Li} 286*760c253cSXin Li 287*760c253cSXin Lifunc TestClangFallbackLinkerPathRelativeToRootDir(t *testing.T) { 288*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 289*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 290*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 291*760c253cSXin Li if err := verifyArgOrder(cmd, "-Bbin"); err != nil { 292*760c253cSXin Li t.Error(err) 293*760c253cSXin Li } 294*760c253cSXin Li if err := verifyArgOrder(cmd, "--prefix=bin/x86_64-cros-linux-gnu-"); err != nil { 295*760c253cSXin Li t.Error(err) 296*760c253cSXin Li } 297*760c253cSXin Li }) 298*760c253cSXin Li} 299*760c253cSXin Li 300*760c253cSXin Lifunc TestClangLinkerPathRelativeToRootDir(t *testing.T) { 301*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 302*760c253cSXin Li ctx.cfg.clangRootRelPath = "somepath" 303*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 304*760c253cSXin Li ctx.newCommand(clangX86_64, mainCc))) 305*760c253cSXin Li if err := verifyArgOrder(cmd, "-Bsomepath/bin"); err != nil { 306*760c253cSXin Li t.Error(err) 307*760c253cSXin Li } 308*760c253cSXin Li if err := verifyArgOrder(cmd, "--prefix=somepath/bin/x86_64-cros-linux-gnu-"); err != nil { 309*760c253cSXin Li t.Error(err) 310*760c253cSXin Li } 311*760c253cSXin Li }) 312*760c253cSXin Li} 313*760c253cSXin Li 314*760c253cSXin Lifunc TestFilterUnsupportedFlags(t *testing.T) { 315*760c253cSXin Li withTestContext(t, func(ctx *testContext) { 316*760c253cSXin Li cmd := ctx.must(callCompiler(ctx, ctx.cfg, 317*760c253cSXin Li ctx.newCommand(clangX86_64, "-Xcompiler", mainCc))) 318*760c253cSXin Li if err := verifyArgCount(cmd, 0, "-Xcompiler"); err != nil { 319*760c253cSXin Li t.Error(err) 320*760c253cSXin Li } 321*760c253cSXin Li cmd = ctx.must(callCompiler(ctx, ctx.cfg, 322*760c253cSXin Li ctx.newCommand(clangX86_64, "-avoid-version", mainCc))) 323*760c253cSXin Li if err := verifyArgCount(cmd, 0, "-avoid-version"); err != nil { 324*760c253cSXin Li t.Error(err) 325*760c253cSXin Li } 326*760c253cSXin Li }) 327*760c253cSXin Li} 328