1// Copyright 2019 The ChromiumOS Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package main 6 7import ( 8 "os" 9 "path" 10 "reflect" 11 "testing" 12) 13 14func TestCommandlineFlagParsing(t *testing.T) { 15 withTestContext(t, func(ctx *testContext) { 16 type testCase struct { 17 extraFlags []string 18 // If this is nonempty, expectedValue is ignored. Otherwise, expectedValue 19 // has the expected value for the flag, and expectedCommand has the expected 20 // (extra) flags in the builder after filtering. 21 expectedError string 22 expectedValue string 23 expectedExtraFlags []string 24 } 25 26 const flagName = "--flag" 27 testCases := []testCase{ 28 { 29 extraFlags: nil, 30 expectedError: errNoSuchCmdlineArg.Error(), 31 }, 32 { 33 extraFlags: []string{flagName + "a"}, 34 expectedError: errNoSuchCmdlineArg.Error(), 35 }, 36 { 37 extraFlags: []string{flagName}, 38 expectedError: "flag \"" + flagName + "\" requires a value", 39 }, 40 { 41 extraFlags: []string{flagName, "foo"}, 42 expectedValue: "foo", 43 expectedExtraFlags: nil, 44 }, 45 { 46 extraFlags: []string{flagName + "=foo"}, 47 expectedValue: "foo", 48 expectedExtraFlags: nil, 49 }, 50 { 51 extraFlags: []string{flagName + "="}, 52 expectedValue: "", 53 expectedExtraFlags: nil, 54 }, 55 { 56 extraFlags: []string{flagName + "=foo", flagName + "=bar"}, 57 expectedValue: "foo", 58 expectedExtraFlags: []string{flagName + "=bar"}, 59 }, 60 } 61 62 for _, testCase := range testCases { 63 cmd := ctx.newCommand(gccX86_64, testCase.extraFlags...) 64 builder, err := newCommandBuilder(ctx, ctx.cfg, cmd) 65 if err != nil { 66 t.Fatalf("Failed creating a command builder: %v", err) 67 } 68 69 flagValue, err := removeOneUserCmdlineFlagWithValue(builder, flagName) 70 if err != nil { 71 if testCase.expectedError == "" { 72 t.Errorf("given extra flags %q, got unexpected error removing %q: %v", testCase.extraFlags, flagName, err) 73 continue 74 } 75 76 if e := err.Error(); e != testCase.expectedError { 77 t.Errorf("given extra flags %q, got error %q; wanted %q", testCase.extraFlags, e, testCase.expectedError) 78 } 79 continue 80 } 81 82 if testCase.expectedError != "" { 83 t.Errorf("given extra flags %q, got no error, but expected %q", testCase.extraFlags, testCase.expectedError) 84 continue 85 } 86 87 if flagValue != testCase.expectedValue { 88 t.Errorf("given extra flags %q, got value %q, but expected %q", testCase.extraFlags, flagValue, testCase.expectedValue) 89 } 90 91 currentFlags := []string{} 92 // Chop off the first arg, which should just be the compiler 93 for _, a := range builder.args { 94 currentFlags = append(currentFlags, a.value) 95 } 96 97 sameFlags := (len(currentFlags) == 0 && len(testCase.expectedExtraFlags) == 0) || reflect.DeepEqual(currentFlags, testCase.expectedExtraFlags) 98 if !sameFlags { 99 t.Errorf("given extra flags %q, got post-removal flags %q, but expected %q", testCase.extraFlags, currentFlags, testCase.expectedExtraFlags) 100 } 101 } 102 }) 103} 104 105func TestCallGomaccIfEnvIsGivenAndValid(t *testing.T) { 106 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 107 ctx.env = []string{"GOMACC_PATH=" + gomaPath} 108 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 109 ctx.newCommand(gccX86_64, mainCc))) 110 if err := verifyPath(cmd, gomaPath); err != nil { 111 t.Error(err) 112 } 113 if err := verifyArgOrder(cmd, gccX86_64+".real", mainCc); err != nil { 114 t.Error(err) 115 } 116 }) 117} 118 119func TestOmitGomaccIfEnvIsGivenButInvalid(t *testing.T) { 120 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 121 if err := os.Remove(gomaPath); err != nil { 122 t.Fatalf("failed removing fake goma file at %q: %v", gomaPath, err) 123 } 124 125 ctx.env = []string{"GOMACC_PATH=" + gomaPath} 126 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 127 ctx.newCommand(gccX86_64, mainCc))) 128 if err := verifyPath(cmd, gccX86_64+".real"); err != nil { 129 t.Error(err) 130 } 131 }) 132} 133 134func TestCallGomaccIfArgIsGivenAndValid(t *testing.T) { 135 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 136 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 137 ctx.newCommand(gccX86_64, mainCc, "--gomacc-path", gomaPath))) 138 if err := verifyPath(cmd, gomaPath); err != nil { 139 t.Error(err) 140 } 141 if err := verifyArgCount(cmd, 0, "--gomacc-path"); err != nil { 142 t.Error(err) 143 } 144 if err := verifyArgCount(cmd, 0, gomaPath); err != nil { 145 t.Error(err) 146 } 147 if err := verifyArgOrder(cmd, gccX86_64+".real", mainCc); err != nil { 148 t.Error(err) 149 } 150 }) 151} 152 153func TestOmitGomaccIfArgIsGivenButInvalid(t *testing.T) { 154 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 155 if err := os.Remove(gomaPath); err != nil { 156 t.Fatalf("failed removing fake goma file at %q: %v", gomaPath, err) 157 } 158 159 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 160 ctx.newCommand(gccX86_64, mainCc, "--gomacc-path", gomaPath))) 161 if err := verifyPath(cmd, gccX86_64+".real"); err != nil { 162 t.Error(err) 163 } 164 }) 165} 166 167func TestErrorOnGomaccArgWithoutValue(t *testing.T) { 168 withTestContext(t, func(ctx *testContext) { 169 stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 170 ctx.newCommand(gccX86_64, mainCc, "--gomacc-path"))) 171 if err := verifyNonInternalError(stderr, "flag \"--gomacc-path\" requires a value"); err != nil { 172 t.Error(err) 173 } 174 }) 175} 176 177func TestOmitGomaccByDefault(t *testing.T) { 178 withTestContext(t, func(ctx *testContext) { 179 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 180 ctx.newCommand(gccX86_64, mainCc))) 181 if err := verifyPath(cmd, gccX86_64+".real"); err != nil { 182 t.Error(err) 183 } 184 }) 185} 186 187func withGomaccTestContext(t *testing.T, f func(*testContext, string)) { 188 withTestContext(t, func(ctx *testContext) { 189 gomaPath := path.Join(ctx.tempDir, "gomacc") 190 // Create a file so the gomacc path is valid. 191 ctx.writeFile(gomaPath, "") 192 f(ctx, gomaPath) 193 }) 194} 195 196func TestRewrapperDefersToTheWrapperProperly(t *testing.T) { 197 withTestContext(t, func(ctx *testContext) { 198 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 199 ctx.newCommand(gccX86_64, mainCc, "--rewrapper-path", "/rewrapper", "--rewrapper-cfg", "/some-cfg", "some", "other", "args"))) 200 if err := verifyPath(cmd, "/rewrapper"); err != nil { 201 t.Error(err) 202 } 203 if err := verifyArgOrder(cmd, "-cfg", "/some-cfg", gccX86_64+".real", mainCc, "some", "other", "args"); err != nil { 204 t.Error(err) 205 } 206 }) 207} 208 209func TestRewrapperCfgMustBePrsentIfRewrapperPathIs(t *testing.T) { 210 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 211 stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 212 ctx.newCommand(gccX86_64, mainCc, "--rewrapper-path", "/rewrapper"))) 213 if err := verifyNonInternalError(stderr, "--rewrapper-cfg must be specified if --rewrapper-path is"); err != nil { 214 t.Error(err) 215 } 216 }) 217} 218 219func TestRewrapperPathMustBePrsentIfRewrapperCfgIs(t *testing.T) { 220 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 221 stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 222 ctx.newCommand(gccX86_64, mainCc, "--rewrapper-cfg", "/some-cfg"))) 223 if err := verifyNonInternalError(stderr, "--rewrapper-path must be specified if --rewrapper-cfg is"); err != nil { 224 t.Error(err) 225 } 226 }) 227} 228 229func TestRewrapperAndGomaAreMutuallyExclusive(t *testing.T) { 230 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 231 stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, 232 ctx.newCommand(gccX86_64, mainCc, "--rewrapper-path", "/rewrapper", "--rewrapper-cfg", "/some-cfg", "--gomacc-path", gomaPath))) 233 if err := verifyNonInternalError(stderr, "rewrapper and gomacc are mutually exclusive"); err != nil { 234 t.Error(err) 235 } 236 }) 237} 238 239func TestRewrapperBlocksGomaInheritanceFromEnv(t *testing.T) { 240 withGomaccTestContext(t, func(ctx *testContext, gomaPath string) { 241 ctx.env = []string{"GOMACC_PATH=" + gomaPath} 242 cmd := ctx.must(callCompiler(ctx, ctx.cfg, 243 ctx.newCommand(gccX86_64, mainCc, "--rewrapper-path", "/rewrapper", "--rewrapper-cfg", "/some-cfg"))) 244 if err := verifyPath(cmd, "/rewrapper"); err != nil { 245 t.Error(err) 246 } 247 if err := verifyArgOrder(cmd, "-cfg", "/some-cfg", gccX86_64+".real", mainCc); err != nil { 248 t.Error(err) 249 } 250 }) 251} 252