xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/remote_build_flag_test.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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