xref: /aosp_15_r20/build/blueprint/ninja_strings_test.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"reflect"
19*1fa6dee9SAndroid Build Coastguard Worker	"slices"
20*1fa6dee9SAndroid Build Coastguard Worker	"strconv"
21*1fa6dee9SAndroid Build Coastguard Worker	"strings"
22*1fa6dee9SAndroid Build Coastguard Worker	"testing"
23*1fa6dee9SAndroid Build Coastguard Worker	"unsafe"
24*1fa6dee9SAndroid Build Coastguard Worker)
25*1fa6dee9SAndroid Build Coastguard Worker
26*1fa6dee9SAndroid Build Coastguard Workertype testVariableRef struct {
27*1fa6dee9SAndroid Build Coastguard Worker	start, end int
28*1fa6dee9SAndroid Build Coastguard Worker	name       string
29*1fa6dee9SAndroid Build Coastguard Worker}
30*1fa6dee9SAndroid Build Coastguard Worker
31*1fa6dee9SAndroid Build Coastguard Workerfunc TestParseNinjaString(t *testing.T) {
32*1fa6dee9SAndroid Build Coastguard Worker	testCases := []struct {
33*1fa6dee9SAndroid Build Coastguard Worker		input string
34*1fa6dee9SAndroid Build Coastguard Worker		vars  []string
35*1fa6dee9SAndroid Build Coastguard Worker		value string
36*1fa6dee9SAndroid Build Coastguard Worker		eval  string
37*1fa6dee9SAndroid Build Coastguard Worker		err   string
38*1fa6dee9SAndroid Build Coastguard Worker	}{
39*1fa6dee9SAndroid Build Coastguard Worker		{
40*1fa6dee9SAndroid Build Coastguard Worker			input: "abc def $ghi jkl",
41*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"ghi"},
42*1fa6dee9SAndroid Build Coastguard Worker			value: "abc def ${namespace.ghi} jkl",
43*1fa6dee9SAndroid Build Coastguard Worker			eval:  "abc def GHI jkl",
44*1fa6dee9SAndroid Build Coastguard Worker		},
45*1fa6dee9SAndroid Build Coastguard Worker		{
46*1fa6dee9SAndroid Build Coastguard Worker			input: "abc def $ghi$jkl",
47*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"ghi", "jkl"},
48*1fa6dee9SAndroid Build Coastguard Worker			value: "abc def ${namespace.ghi}${namespace.jkl}",
49*1fa6dee9SAndroid Build Coastguard Worker			eval:  "abc def GHIJKL",
50*1fa6dee9SAndroid Build Coastguard Worker		},
51*1fa6dee9SAndroid Build Coastguard Worker		{
52*1fa6dee9SAndroid Build Coastguard Worker			input: "foo $012_-345xyz_! bar",
53*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"012_-345xyz_"},
54*1fa6dee9SAndroid Build Coastguard Worker			value: "foo ${namespace.012_-345xyz_}! bar",
55*1fa6dee9SAndroid Build Coastguard Worker			eval:  "foo 012_-345XYZ_! bar",
56*1fa6dee9SAndroid Build Coastguard Worker		},
57*1fa6dee9SAndroid Build Coastguard Worker		{
58*1fa6dee9SAndroid Build Coastguard Worker			input: "foo ${012_-345xyz_} bar",
59*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"012_-345xyz_"},
60*1fa6dee9SAndroid Build Coastguard Worker			value: "foo ${namespace.012_-345xyz_} bar",
61*1fa6dee9SAndroid Build Coastguard Worker			eval:  "foo 012_-345XYZ_ bar",
62*1fa6dee9SAndroid Build Coastguard Worker		},
63*1fa6dee9SAndroid Build Coastguard Worker		{
64*1fa6dee9SAndroid Build Coastguard Worker			input: "foo ${012_-345xyz_} bar",
65*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"012_-345xyz_"},
66*1fa6dee9SAndroid Build Coastguard Worker			value: "foo ${namespace.012_-345xyz_} bar",
67*1fa6dee9SAndroid Build Coastguard Worker			eval:  "foo 012_-345XYZ_ bar",
68*1fa6dee9SAndroid Build Coastguard Worker		},
69*1fa6dee9SAndroid Build Coastguard Worker		{
70*1fa6dee9SAndroid Build Coastguard Worker			input: "foo $$ bar",
71*1fa6dee9SAndroid Build Coastguard Worker			vars:  nil,
72*1fa6dee9SAndroid Build Coastguard Worker			value: "foo $$ bar",
73*1fa6dee9SAndroid Build Coastguard Worker			eval:  "foo $$ bar",
74*1fa6dee9SAndroid Build Coastguard Worker		},
75*1fa6dee9SAndroid Build Coastguard Worker		{
76*1fa6dee9SAndroid Build Coastguard Worker			input: "$foo${bar}",
77*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"foo", "bar"},
78*1fa6dee9SAndroid Build Coastguard Worker			value: "${namespace.foo}${namespace.bar}",
79*1fa6dee9SAndroid Build Coastguard Worker			eval:  "FOOBAR",
80*1fa6dee9SAndroid Build Coastguard Worker		},
81*1fa6dee9SAndroid Build Coastguard Worker		{
82*1fa6dee9SAndroid Build Coastguard Worker			input: "$foo$$",
83*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"foo"},
84*1fa6dee9SAndroid Build Coastguard Worker			value: "${namespace.foo}$$",
85*1fa6dee9SAndroid Build Coastguard Worker			eval:  "FOO$$",
86*1fa6dee9SAndroid Build Coastguard Worker		},
87*1fa6dee9SAndroid Build Coastguard Worker		{
88*1fa6dee9SAndroid Build Coastguard Worker			input: "foo bar",
89*1fa6dee9SAndroid Build Coastguard Worker			vars:  nil,
90*1fa6dee9SAndroid Build Coastguard Worker			value: "foo bar",
91*1fa6dee9SAndroid Build Coastguard Worker			eval:  "foo bar",
92*1fa6dee9SAndroid Build Coastguard Worker		},
93*1fa6dee9SAndroid Build Coastguard Worker		{
94*1fa6dee9SAndroid Build Coastguard Worker			input: " foo ",
95*1fa6dee9SAndroid Build Coastguard Worker			vars:  nil,
96*1fa6dee9SAndroid Build Coastguard Worker			value: "$ foo ",
97*1fa6dee9SAndroid Build Coastguard Worker			eval:  "$ foo ",
98*1fa6dee9SAndroid Build Coastguard Worker		},
99*1fa6dee9SAndroid Build Coastguard Worker		{
100*1fa6dee9SAndroid Build Coastguard Worker			input: "\tfoo ",
101*1fa6dee9SAndroid Build Coastguard Worker			vars:  nil,
102*1fa6dee9SAndroid Build Coastguard Worker			value: "\tfoo ",
103*1fa6dee9SAndroid Build Coastguard Worker			eval:  "\tfoo ",
104*1fa6dee9SAndroid Build Coastguard Worker		},
105*1fa6dee9SAndroid Build Coastguard Worker		{
106*1fa6dee9SAndroid Build Coastguard Worker			input: "\nfoo ",
107*1fa6dee9SAndroid Build Coastguard Worker			vars:  nil,
108*1fa6dee9SAndroid Build Coastguard Worker			value: "$\nfoo ",
109*1fa6dee9SAndroid Build Coastguard Worker			eval:  "\nfoo ",
110*1fa6dee9SAndroid Build Coastguard Worker		},
111*1fa6dee9SAndroid Build Coastguard Worker		{
112*1fa6dee9SAndroid Build Coastguard Worker			input: " $foo ",
113*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"foo"},
114*1fa6dee9SAndroid Build Coastguard Worker			value: "$ ${namespace.foo} ",
115*1fa6dee9SAndroid Build Coastguard Worker			eval:  " FOO ",
116*1fa6dee9SAndroid Build Coastguard Worker		},
117*1fa6dee9SAndroid Build Coastguard Worker		{
118*1fa6dee9SAndroid Build Coastguard Worker			input: "\t$foo ",
119*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"foo"},
120*1fa6dee9SAndroid Build Coastguard Worker			value: "\t${namespace.foo} ",
121*1fa6dee9SAndroid Build Coastguard Worker			eval:  "\tFOO ",
122*1fa6dee9SAndroid Build Coastguard Worker		},
123*1fa6dee9SAndroid Build Coastguard Worker		{
124*1fa6dee9SAndroid Build Coastguard Worker			input: "\n$foo ",
125*1fa6dee9SAndroid Build Coastguard Worker			vars:  []string{"foo"},
126*1fa6dee9SAndroid Build Coastguard Worker			value: "$\n${namespace.foo} ",
127*1fa6dee9SAndroid Build Coastguard Worker			eval:  "\nFOO ",
128*1fa6dee9SAndroid Build Coastguard Worker		},
129*1fa6dee9SAndroid Build Coastguard Worker		{
130*1fa6dee9SAndroid Build Coastguard Worker			input: "foo $ bar",
131*1fa6dee9SAndroid Build Coastguard Worker			err:   `error parsing ninja string "foo $ bar": invalid character after '$' at byte offset 5`,
132*1fa6dee9SAndroid Build Coastguard Worker		},
133*1fa6dee9SAndroid Build Coastguard Worker		{
134*1fa6dee9SAndroid Build Coastguard Worker			input: "foo $",
135*1fa6dee9SAndroid Build Coastguard Worker			err:   "unexpected end of string after '$'",
136*1fa6dee9SAndroid Build Coastguard Worker		},
137*1fa6dee9SAndroid Build Coastguard Worker		{
138*1fa6dee9SAndroid Build Coastguard Worker			input: "foo ${} bar",
139*1fa6dee9SAndroid Build Coastguard Worker			err:   `error parsing ninja string "foo ${} bar": empty variable name at byte offset 6`,
140*1fa6dee9SAndroid Build Coastguard Worker		},
141*1fa6dee9SAndroid Build Coastguard Worker		{
142*1fa6dee9SAndroid Build Coastguard Worker			input: "foo ${abc!} bar",
143*1fa6dee9SAndroid Build Coastguard Worker			err:   `error parsing ninja string "foo ${abc!} bar": invalid character in variable name at byte offset 9`,
144*1fa6dee9SAndroid Build Coastguard Worker		},
145*1fa6dee9SAndroid Build Coastguard Worker		{
146*1fa6dee9SAndroid Build Coastguard Worker			input: "foo ${abc",
147*1fa6dee9SAndroid Build Coastguard Worker			err:   "unexpected end of string in variable name",
148*1fa6dee9SAndroid Build Coastguard Worker		},
149*1fa6dee9SAndroid Build Coastguard Worker	}
150*1fa6dee9SAndroid Build Coastguard Worker
151*1fa6dee9SAndroid Build Coastguard Worker	for _, testCase := range testCases {
152*1fa6dee9SAndroid Build Coastguard Worker		t.Run(testCase.input, func(t *testing.T) {
153*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "namespace.")
154*1fa6dee9SAndroid Build Coastguard Worker			variablesMap := map[Variable]*ninjaString{}
155*1fa6dee9SAndroid Build Coastguard Worker			for _, varName := range testCase.vars {
156*1fa6dee9SAndroid Build Coastguard Worker				_, err := scope.LookupVariable(varName)
157*1fa6dee9SAndroid Build Coastguard Worker				if err != nil {
158*1fa6dee9SAndroid Build Coastguard Worker					v, err := scope.AddLocalVariable(varName, strings.ToUpper(varName))
159*1fa6dee9SAndroid Build Coastguard Worker					if err != nil {
160*1fa6dee9SAndroid Build Coastguard Worker						t.Fatalf("error creating scope: %s", err)
161*1fa6dee9SAndroid Build Coastguard Worker					}
162*1fa6dee9SAndroid Build Coastguard Worker					variablesMap[v] = simpleNinjaString(strings.ToUpper(varName))
163*1fa6dee9SAndroid Build Coastguard Worker				}
164*1fa6dee9SAndroid Build Coastguard Worker			}
165*1fa6dee9SAndroid Build Coastguard Worker
166*1fa6dee9SAndroid Build Coastguard Worker			output, err := parseNinjaString(scope, testCase.input)
167*1fa6dee9SAndroid Build Coastguard Worker			if err == nil {
168*1fa6dee9SAndroid Build Coastguard Worker				if g, w := output.Value(&nameTracker{}), testCase.value; g != w {
169*1fa6dee9SAndroid Build Coastguard Worker					t.Errorf("incorrect Value output, want %q, got %q", w, g)
170*1fa6dee9SAndroid Build Coastguard Worker				}
171*1fa6dee9SAndroid Build Coastguard Worker
172*1fa6dee9SAndroid Build Coastguard Worker				eval, err := output.Eval(variablesMap)
173*1fa6dee9SAndroid Build Coastguard Worker				if err != nil {
174*1fa6dee9SAndroid Build Coastguard Worker					t.Errorf("unexpected error in Eval: %s", err)
175*1fa6dee9SAndroid Build Coastguard Worker				}
176*1fa6dee9SAndroid Build Coastguard Worker				if g, w := eval, testCase.eval; g != w {
177*1fa6dee9SAndroid Build Coastguard Worker					t.Errorf("incorrect Eval output, want %q, got %q", w, g)
178*1fa6dee9SAndroid Build Coastguard Worker				}
179*1fa6dee9SAndroid Build Coastguard Worker			}
180*1fa6dee9SAndroid Build Coastguard Worker			var errStr string
181*1fa6dee9SAndroid Build Coastguard Worker			if err != nil {
182*1fa6dee9SAndroid Build Coastguard Worker				errStr = err.Error()
183*1fa6dee9SAndroid Build Coastguard Worker			}
184*1fa6dee9SAndroid Build Coastguard Worker			if err != nil && err.Error() != testCase.err {
185*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("unexpected error:")
186*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("     input: %q", testCase.input)
187*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("  expected: %q", testCase.err)
188*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("       got: %q", errStr)
189*1fa6dee9SAndroid Build Coastguard Worker			}
190*1fa6dee9SAndroid Build Coastguard Worker		})
191*1fa6dee9SAndroid Build Coastguard Worker	}
192*1fa6dee9SAndroid Build Coastguard Worker}
193*1fa6dee9SAndroid Build Coastguard Worker
194*1fa6dee9SAndroid Build Coastguard Workerfunc TestParseNinjaStringWithImportedVar(t *testing.T) {
195*1fa6dee9SAndroid Build Coastguard Worker	pctx := &packageContext{}
196*1fa6dee9SAndroid Build Coastguard Worker	pkgNames := map[*packageContext]string{
197*1fa6dee9SAndroid Build Coastguard Worker		pctx: "impPkg",
198*1fa6dee9SAndroid Build Coastguard Worker	}
199*1fa6dee9SAndroid Build Coastguard Worker	ImpVar := &staticVariable{pctx: pctx, name_: "ImpVar"}
200*1fa6dee9SAndroid Build Coastguard Worker	impScope := newScope(nil)
201*1fa6dee9SAndroid Build Coastguard Worker	impScope.AddVariable(ImpVar)
202*1fa6dee9SAndroid Build Coastguard Worker	scope := newScope(nil)
203*1fa6dee9SAndroid Build Coastguard Worker	scope.AddImport("impPkg", impScope)
204*1fa6dee9SAndroid Build Coastguard Worker
205*1fa6dee9SAndroid Build Coastguard Worker	input := "abc def ${impPkg.ImpVar} ghi"
206*1fa6dee9SAndroid Build Coastguard Worker	output, err := parseNinjaString(scope, input)
207*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
208*1fa6dee9SAndroid Build Coastguard Worker		t.Fatalf("unexpected error: %s", err)
209*1fa6dee9SAndroid Build Coastguard Worker	}
210*1fa6dee9SAndroid Build Coastguard Worker
211*1fa6dee9SAndroid Build Coastguard Worker	expect := []variableReference{{8, 24, ImpVar}}
212*1fa6dee9SAndroid Build Coastguard Worker	if !reflect.DeepEqual(*output.variables, expect) {
213*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("incorrect output:")
214*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("     input: %q", input)
215*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("  expected: %#v", expect)
216*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("       got: %#v", *output.variables)
217*1fa6dee9SAndroid Build Coastguard Worker	}
218*1fa6dee9SAndroid Build Coastguard Worker
219*1fa6dee9SAndroid Build Coastguard Worker	if g, w := output.Value(&nameTracker{pkgNames: pkgNames}), "abc def ${g.impPkg.ImpVar} ghi"; g != w {
220*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("incorrect Value output, want %q got %q", w, g)
221*1fa6dee9SAndroid Build Coastguard Worker	}
222*1fa6dee9SAndroid Build Coastguard Worker}
223*1fa6dee9SAndroid Build Coastguard Worker
224*1fa6dee9SAndroid Build Coastguard Workerfunc Test_parseNinjaOrSimpleStrings(t *testing.T) {
225*1fa6dee9SAndroid Build Coastguard Worker	testCases := []struct {
226*1fa6dee9SAndroid Build Coastguard Worker		name            string
227*1fa6dee9SAndroid Build Coastguard Worker		in              []string
228*1fa6dee9SAndroid Build Coastguard Worker		outStrings      []string
229*1fa6dee9SAndroid Build Coastguard Worker		outNinjaStrings []string
230*1fa6dee9SAndroid Build Coastguard Worker		sameSlice       bool
231*1fa6dee9SAndroid Build Coastguard Worker	}{
232*1fa6dee9SAndroid Build Coastguard Worker		{
233*1fa6dee9SAndroid Build Coastguard Worker			name:      "nil",
234*1fa6dee9SAndroid Build Coastguard Worker			in:        nil,
235*1fa6dee9SAndroid Build Coastguard Worker			sameSlice: true,
236*1fa6dee9SAndroid Build Coastguard Worker		},
237*1fa6dee9SAndroid Build Coastguard Worker		{
238*1fa6dee9SAndroid Build Coastguard Worker			name:      "empty",
239*1fa6dee9SAndroid Build Coastguard Worker			in:        []string{},
240*1fa6dee9SAndroid Build Coastguard Worker			sameSlice: true,
241*1fa6dee9SAndroid Build Coastguard Worker		},
242*1fa6dee9SAndroid Build Coastguard Worker		{
243*1fa6dee9SAndroid Build Coastguard Worker			name:      "string",
244*1fa6dee9SAndroid Build Coastguard Worker			in:        []string{"abc"},
245*1fa6dee9SAndroid Build Coastguard Worker			sameSlice: true,
246*1fa6dee9SAndroid Build Coastguard Worker		},
247*1fa6dee9SAndroid Build Coastguard Worker		{
248*1fa6dee9SAndroid Build Coastguard Worker			name:            "ninja string",
249*1fa6dee9SAndroid Build Coastguard Worker			in:              []string{"$abc"},
250*1fa6dee9SAndroid Build Coastguard Worker			outStrings:      nil,
251*1fa6dee9SAndroid Build Coastguard Worker			outNinjaStrings: []string{"${abc}"},
252*1fa6dee9SAndroid Build Coastguard Worker		},
253*1fa6dee9SAndroid Build Coastguard Worker		{
254*1fa6dee9SAndroid Build Coastguard Worker			name:            "ninja string first",
255*1fa6dee9SAndroid Build Coastguard Worker			in:              []string{"$abc", "def", "ghi"},
256*1fa6dee9SAndroid Build Coastguard Worker			outStrings:      []string{"def", "ghi"},
257*1fa6dee9SAndroid Build Coastguard Worker			outNinjaStrings: []string{"${abc}"},
258*1fa6dee9SAndroid Build Coastguard Worker		},
259*1fa6dee9SAndroid Build Coastguard Worker		{
260*1fa6dee9SAndroid Build Coastguard Worker			name:            "ninja string middle",
261*1fa6dee9SAndroid Build Coastguard Worker			in:              []string{"abc", "$def", "ghi"},
262*1fa6dee9SAndroid Build Coastguard Worker			outStrings:      []string{"abc", "ghi"},
263*1fa6dee9SAndroid Build Coastguard Worker			outNinjaStrings: []string{"${def}"},
264*1fa6dee9SAndroid Build Coastguard Worker		},
265*1fa6dee9SAndroid Build Coastguard Worker		{
266*1fa6dee9SAndroid Build Coastguard Worker			name:            "ninja string last",
267*1fa6dee9SAndroid Build Coastguard Worker			in:              []string{"abc", "def", "$ghi"},
268*1fa6dee9SAndroid Build Coastguard Worker			outStrings:      []string{"abc", "def"},
269*1fa6dee9SAndroid Build Coastguard Worker			outNinjaStrings: []string{"${ghi}"},
270*1fa6dee9SAndroid Build Coastguard Worker		},
271*1fa6dee9SAndroid Build Coastguard Worker	}
272*1fa6dee9SAndroid Build Coastguard Worker
273*1fa6dee9SAndroid Build Coastguard Worker	for _, tt := range testCases {
274*1fa6dee9SAndroid Build Coastguard Worker		t.Run(tt.name, func(t *testing.T) {
275*1fa6dee9SAndroid Build Coastguard Worker			inCopy := slices.Clone(tt.in)
276*1fa6dee9SAndroid Build Coastguard Worker
277*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "")
278*1fa6dee9SAndroid Build Coastguard Worker			scope.AddLocalVariable("abc", "abc")
279*1fa6dee9SAndroid Build Coastguard Worker			scope.AddLocalVariable("def", "def")
280*1fa6dee9SAndroid Build Coastguard Worker			scope.AddLocalVariable("ghi", "ghi")
281*1fa6dee9SAndroid Build Coastguard Worker			gotNinjaStrings, gotStrings, err := parseNinjaOrSimpleStrings(scope, tt.in)
282*1fa6dee9SAndroid Build Coastguard Worker			if err != nil {
283*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("unexpected error %s", err)
284*1fa6dee9SAndroid Build Coastguard Worker			}
285*1fa6dee9SAndroid Build Coastguard Worker
286*1fa6dee9SAndroid Build Coastguard Worker			wantStrings := tt.outStrings
287*1fa6dee9SAndroid Build Coastguard Worker			if tt.sameSlice {
288*1fa6dee9SAndroid Build Coastguard Worker				wantStrings = tt.in
289*1fa6dee9SAndroid Build Coastguard Worker			}
290*1fa6dee9SAndroid Build Coastguard Worker
291*1fa6dee9SAndroid Build Coastguard Worker			wantNinjaStrings := tt.outNinjaStrings
292*1fa6dee9SAndroid Build Coastguard Worker
293*1fa6dee9SAndroid Build Coastguard Worker			var evaluatedNinjaStrings []string
294*1fa6dee9SAndroid Build Coastguard Worker			if gotNinjaStrings != nil {
295*1fa6dee9SAndroid Build Coastguard Worker				evaluatedNinjaStrings = make([]string, 0, len(gotNinjaStrings))
296*1fa6dee9SAndroid Build Coastguard Worker				for _, ns := range gotNinjaStrings {
297*1fa6dee9SAndroid Build Coastguard Worker					evaluatedNinjaStrings = append(evaluatedNinjaStrings, ns.Value(&nameTracker{}))
298*1fa6dee9SAndroid Build Coastguard Worker				}
299*1fa6dee9SAndroid Build Coastguard Worker			}
300*1fa6dee9SAndroid Build Coastguard Worker
301*1fa6dee9SAndroid Build Coastguard Worker			if !reflect.DeepEqual(gotStrings, wantStrings) {
302*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("incorrect strings output, want %q got %q", wantStrings, gotStrings)
303*1fa6dee9SAndroid Build Coastguard Worker			}
304*1fa6dee9SAndroid Build Coastguard Worker			if !reflect.DeepEqual(evaluatedNinjaStrings, wantNinjaStrings) {
305*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("incorrect ninja strings output, want %q got %q", wantNinjaStrings, evaluatedNinjaStrings)
306*1fa6dee9SAndroid Build Coastguard Worker			}
307*1fa6dee9SAndroid Build Coastguard Worker			if len(inCopy) != len(tt.in) && (len(tt.in) == 0 || !reflect.DeepEqual(inCopy, tt.in)) {
308*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf("input modified, want %#v, got %#v", inCopy, tt.in)
309*1fa6dee9SAndroid Build Coastguard Worker			}
310*1fa6dee9SAndroid Build Coastguard Worker
311*1fa6dee9SAndroid Build Coastguard Worker			if (unsafe.SliceData(tt.in) == unsafe.SliceData(gotStrings)) != tt.sameSlice {
312*1fa6dee9SAndroid Build Coastguard Worker				if tt.sameSlice {
313*1fa6dee9SAndroid Build Coastguard Worker					t.Errorf("expected input and output slices to have the same backing arrays")
314*1fa6dee9SAndroid Build Coastguard Worker				} else {
315*1fa6dee9SAndroid Build Coastguard Worker					t.Errorf("expected input and output slices to have different backing arrays")
316*1fa6dee9SAndroid Build Coastguard Worker				}
317*1fa6dee9SAndroid Build Coastguard Worker			}
318*1fa6dee9SAndroid Build Coastguard Worker
319*1fa6dee9SAndroid Build Coastguard Worker		})
320*1fa6dee9SAndroid Build Coastguard Worker	}
321*1fa6dee9SAndroid Build Coastguard Worker}
322*1fa6dee9SAndroid Build Coastguard Worker
323*1fa6dee9SAndroid Build Coastguard Workerfunc Benchmark_parseNinjaString(b *testing.B) {
324*1fa6dee9SAndroid Build Coastguard Worker	b.Run("constant", func(b *testing.B) {
325*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 10, 100, 1000} {
326*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
327*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
328*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
329*1fa6dee9SAndroid Build Coastguard Worker					_ = simpleNinjaString(strings.Repeat("a", l))
330*1fa6dee9SAndroid Build Coastguard Worker				}
331*1fa6dee9SAndroid Build Coastguard Worker			})
332*1fa6dee9SAndroid Build Coastguard Worker		}
333*1fa6dee9SAndroid Build Coastguard Worker	})
334*1fa6dee9SAndroid Build Coastguard Worker	b.Run("variable", func(b *testing.B) {
335*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 10, 100, 1000} {
336*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "")
337*1fa6dee9SAndroid Build Coastguard Worker			scope.AddLocalVariable("a", strings.Repeat("b", l/3))
338*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
339*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
340*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
341*1fa6dee9SAndroid Build Coastguard Worker					_, _ = parseNinjaString(scope, strings.Repeat("a", l/3)+"${a}"+strings.Repeat("a", l/3))
342*1fa6dee9SAndroid Build Coastguard Worker				}
343*1fa6dee9SAndroid Build Coastguard Worker			})
344*1fa6dee9SAndroid Build Coastguard Worker		}
345*1fa6dee9SAndroid Build Coastguard Worker	})
346*1fa6dee9SAndroid Build Coastguard Worker	b.Run("variables", func(b *testing.B) {
347*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 2, 3, 4, 5, 10, 100, 1000} {
348*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "")
349*1fa6dee9SAndroid Build Coastguard Worker			str := strings.Repeat("a", 10)
350*1fa6dee9SAndroid Build Coastguard Worker			for i := 0; i < l; i++ {
351*1fa6dee9SAndroid Build Coastguard Worker				scope.AddLocalVariable("a"+strconv.Itoa(i), strings.Repeat("b", 10))
352*1fa6dee9SAndroid Build Coastguard Worker				str += "${a" + strconv.Itoa(i) + "}"
353*1fa6dee9SAndroid Build Coastguard Worker			}
354*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
355*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
356*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
357*1fa6dee9SAndroid Build Coastguard Worker					_, _ = parseNinjaString(scope, str)
358*1fa6dee9SAndroid Build Coastguard Worker				}
359*1fa6dee9SAndroid Build Coastguard Worker			})
360*1fa6dee9SAndroid Build Coastguard Worker		}
361*1fa6dee9SAndroid Build Coastguard Worker	})
362*1fa6dee9SAndroid Build Coastguard Worker
363*1fa6dee9SAndroid Build Coastguard Worker}
364*1fa6dee9SAndroid Build Coastguard Worker
365*1fa6dee9SAndroid Build Coastguard Workerfunc BenchmarkNinjaString_Value(b *testing.B) {
366*1fa6dee9SAndroid Build Coastguard Worker	b.Run("constant", func(b *testing.B) {
367*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 10, 100, 1000} {
368*1fa6dee9SAndroid Build Coastguard Worker			ns := simpleNinjaString(strings.Repeat("a", l))
369*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
370*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
371*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
372*1fa6dee9SAndroid Build Coastguard Worker					ns.Value(&nameTracker{})
373*1fa6dee9SAndroid Build Coastguard Worker				}
374*1fa6dee9SAndroid Build Coastguard Worker			})
375*1fa6dee9SAndroid Build Coastguard Worker		}
376*1fa6dee9SAndroid Build Coastguard Worker	})
377*1fa6dee9SAndroid Build Coastguard Worker	b.Run("variable", func(b *testing.B) {
378*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 10, 100, 1000} {
379*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "")
380*1fa6dee9SAndroid Build Coastguard Worker			scope.AddLocalVariable("a", strings.Repeat("b", l/3))
381*1fa6dee9SAndroid Build Coastguard Worker			ns, _ := parseNinjaString(scope, strings.Repeat("a", l/3)+"${a}"+strings.Repeat("a", l/3))
382*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
383*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
384*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
385*1fa6dee9SAndroid Build Coastguard Worker					ns.Value(&nameTracker{})
386*1fa6dee9SAndroid Build Coastguard Worker				}
387*1fa6dee9SAndroid Build Coastguard Worker			})
388*1fa6dee9SAndroid Build Coastguard Worker		}
389*1fa6dee9SAndroid Build Coastguard Worker	})
390*1fa6dee9SAndroid Build Coastguard Worker	b.Run("variables", func(b *testing.B) {
391*1fa6dee9SAndroid Build Coastguard Worker		for _, l := range []int{1, 2, 3, 4, 5, 10, 100, 1000} {
392*1fa6dee9SAndroid Build Coastguard Worker			scope := newLocalScope(nil, "")
393*1fa6dee9SAndroid Build Coastguard Worker			str := strings.Repeat("a", 10)
394*1fa6dee9SAndroid Build Coastguard Worker			for i := 0; i < l; i++ {
395*1fa6dee9SAndroid Build Coastguard Worker				scope.AddLocalVariable("a"+strconv.Itoa(i), strings.Repeat("b", 10))
396*1fa6dee9SAndroid Build Coastguard Worker				str += "${a" + strconv.Itoa(i) + "}"
397*1fa6dee9SAndroid Build Coastguard Worker			}
398*1fa6dee9SAndroid Build Coastguard Worker			ns, _ := parseNinjaString(scope, str)
399*1fa6dee9SAndroid Build Coastguard Worker			b.Run(strconv.Itoa(l), func(b *testing.B) {
400*1fa6dee9SAndroid Build Coastguard Worker				b.ReportAllocs()
401*1fa6dee9SAndroid Build Coastguard Worker				for n := 0; n < b.N; n++ {
402*1fa6dee9SAndroid Build Coastguard Worker					ns.Value(&nameTracker{})
403*1fa6dee9SAndroid Build Coastguard Worker				}
404*1fa6dee9SAndroid Build Coastguard Worker			})
405*1fa6dee9SAndroid Build Coastguard Worker		}
406*1fa6dee9SAndroid Build Coastguard Worker	})
407*1fa6dee9SAndroid Build Coastguard Worker
408*1fa6dee9SAndroid Build Coastguard Worker}
409