Add tests for genrule command expansion
Add tests for expanding variables in a genrule cmd property. Test: genrule_test.go Change-Id: I8288b8616d518bb5f24a892c4e59f68d95055d0a
This commit is contained in:
parent
ecdeb1e705
commit
2a07692643
4 changed files with 383 additions and 2 deletions
|
@ -192,6 +192,9 @@ bootstrap_go_package {
|
|||
srcs: [
|
||||
"genrule/genrule.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"genrule/genrule_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
}
|
||||
|
||||
|
|
|
@ -241,6 +241,8 @@ func TestArchConfig(buildDir string, env map[string]string) Config {
|
|||
},
|
||||
}
|
||||
|
||||
config.BuildOsVariant = config.Targets[Host][0].String()
|
||||
|
||||
return testConfig
|
||||
}
|
||||
|
||||
|
|
|
@ -102,8 +102,9 @@ type Module struct {
|
|||
|
||||
taskGenerator taskFunc
|
||||
|
||||
deps android.Paths
|
||||
rule blueprint.Rule
|
||||
deps android.Paths
|
||||
rule blueprint.Rule
|
||||
rawCommand string
|
||||
|
||||
exportedIncludeDirs android.Paths
|
||||
|
||||
|
@ -287,6 +288,7 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
genDir := android.PathForModuleGen(ctx)
|
||||
// Escape the command for the shell
|
||||
rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
|
||||
g.rawCommand = rawCommand
|
||||
sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
|
||||
sandboxPath, genDir, rawCommand, depfilePlaceholder)
|
||||
|
||||
|
|
374
genrule/genrule_test.go
Normal file
374
genrule/genrule_test.go
Normal file
|
@ -0,0 +1,374 @@
|
|||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package genrule
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
var buildDir string
|
||||
|
||||
func setUp() {
|
||||
var err error
|
||||
buildDir, err = ioutil.TempDir("", "soong_java_test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
os.RemoveAll(buildDir)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
run := func() int {
|
||||
setUp()
|
||||
defer tearDown()
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
os.Exit(run())
|
||||
}
|
||||
|
||||
func testContext(config android.Config, bp string,
|
||||
fs map[string][]byte) *android.TestContext {
|
||||
|
||||
ctx := android.NewTestArchContext()
|
||||
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
|
||||
ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(GenRuleFactory))
|
||||
ctx.RegisterModuleType("tool", android.ModuleFactoryAdaptor(toolFactory))
|
||||
ctx.Register()
|
||||
|
||||
bp += `
|
||||
tool {
|
||||
name: "tool",
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "tool_files",
|
||||
srcs: [
|
||||
"tool_file1",
|
||||
"tool_file2",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "1tool_file",
|
||||
srcs: [
|
||||
"tool_file1",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "ins",
|
||||
srcs: [
|
||||
"in1",
|
||||
"in2",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "1in",
|
||||
srcs: [
|
||||
"in1",
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "empty",
|
||||
}
|
||||
`
|
||||
|
||||
mockFS := map[string][]byte{
|
||||
"Android.bp": []byte(bp),
|
||||
"tool": nil,
|
||||
"tool_file1": nil,
|
||||
"tool_file2": nil,
|
||||
"in1": nil,
|
||||
"in2": nil,
|
||||
}
|
||||
|
||||
for k, v := range fs {
|
||||
mockFS[k] = v
|
||||
}
|
||||
|
||||
ctx.MockFileSystem(mockFS)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func TestGenruleCmd(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
prop string
|
||||
|
||||
err string
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
name: "empty location tool",
|
||||
prop: `
|
||||
tools: ["tool"],
|
||||
out: ["out"],
|
||||
cmd: "$(location) > $(out)",
|
||||
`,
|
||||
expect: "out/tool > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "empty location tool file",
|
||||
prop: `
|
||||
tool_files: ["tool_file1"],
|
||||
out: ["out"],
|
||||
cmd: "$(location) > $(out)",
|
||||
`,
|
||||
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "empty location tool file fg",
|
||||
prop: `
|
||||
tool_files: [":1tool_file"],
|
||||
out: ["out"],
|
||||
cmd: "$(location) > $(out)",
|
||||
`,
|
||||
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "empty location tool and tool file",
|
||||
prop: `
|
||||
tools: ["tool"],
|
||||
tool_files: ["tool_file1"],
|
||||
out: ["out"],
|
||||
cmd: "$(location) > $(out)",
|
||||
`,
|
||||
expect: "out/tool > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "tool",
|
||||
prop: `
|
||||
tools: ["tool"],
|
||||
out: ["out"],
|
||||
cmd: "$(location tool) > $(out)",
|
||||
`,
|
||||
expect: "out/tool > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "tool file",
|
||||
prop: `
|
||||
tool_files: ["tool_file1"],
|
||||
out: ["out"],
|
||||
cmd: "$(location tool_file1) > $(out)",
|
||||
`,
|
||||
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "tool file fg",
|
||||
prop: `
|
||||
tool_files: [":1tool_file"],
|
||||
out: ["out"],
|
||||
cmd: "$(location tool_file1) > $(out)",
|
||||
`,
|
||||
expect: "tool_file1 > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "tool files",
|
||||
prop: `
|
||||
tool_files: [":tool_files"],
|
||||
out: ["out"],
|
||||
cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
|
||||
`,
|
||||
expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "in1",
|
||||
prop: `
|
||||
srcs: ["in1"],
|
||||
out: ["out"],
|
||||
cmd: "cat $(in) > $(out)",
|
||||
`,
|
||||
expect: "cat ${in} > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "in1 fg",
|
||||
prop: `
|
||||
srcs: [":1in"],
|
||||
out: ["out"],
|
||||
cmd: "cat $(in) > $(out)",
|
||||
`,
|
||||
expect: "cat ${in} > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "ins",
|
||||
prop: `
|
||||
srcs: ["in1", "in2"],
|
||||
out: ["out"],
|
||||
cmd: "cat $(in) > $(out)",
|
||||
`,
|
||||
expect: "cat ${in} > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "ins fg",
|
||||
prop: `
|
||||
srcs: [":ins"],
|
||||
out: ["out"],
|
||||
cmd: "cat $(in) > $(out)",
|
||||
`,
|
||||
expect: "cat ${in} > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "outs",
|
||||
prop: `
|
||||
out: ["out", "out2"],
|
||||
cmd: "echo foo > $(out)",
|
||||
`,
|
||||
expect: "echo foo > __SBOX_OUT_FILES__",
|
||||
},
|
||||
{
|
||||
name: "depfile",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
depfile: true,
|
||||
cmd: "echo foo > $(out) && touch $(depfile)",
|
||||
`,
|
||||
expect: "echo foo > __SBOX_OUT_FILES__ && touch __SBOX_DEPFILE__",
|
||||
},
|
||||
{
|
||||
name: "gendir",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
|
||||
`,
|
||||
expect: "echo foo > __SBOX_OUT_DIR__/foo && cp __SBOX_OUT_DIR__/foo __SBOX_OUT_FILES__",
|
||||
},
|
||||
|
||||
{
|
||||
name: "error empty location",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
cmd: "$(location) > $(out)",
|
||||
`,
|
||||
err: "at least one `tools` or `tool_files` is required if $(location) is used",
|
||||
},
|
||||
{
|
||||
name: "error location",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
cmd: "echo foo > $(location missing)",
|
||||
`,
|
||||
err: `unknown location label "missing"`,
|
||||
},
|
||||
{
|
||||
name: "error variable",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
srcs: ["in1"],
|
||||
cmd: "echo $(foo) > $(out)",
|
||||
`,
|
||||
err: `unknown variable '$(foo)'`,
|
||||
},
|
||||
{
|
||||
name: "error depfile",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
cmd: "echo foo > $(out) && touch $(depfile)",
|
||||
`,
|
||||
err: "$(depfile) used without depfile property",
|
||||
},
|
||||
{
|
||||
name: "error no depfile",
|
||||
prop: `
|
||||
out: ["out"],
|
||||
depfile: true,
|
||||
cmd: "echo foo > $(out)",
|
||||
`,
|
||||
err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
|
||||
},
|
||||
{
|
||||
name: "error no out",
|
||||
prop: `
|
||||
cmd: "echo foo > $(out)",
|
||||
`,
|
||||
err: "must have at least one output file",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testcases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
config := android.TestArchConfig(buildDir, nil)
|
||||
bp := "genrule {\n"
|
||||
bp += "name: \"gen\",\n"
|
||||
bp += test.prop
|
||||
bp += "}\n"
|
||||
|
||||
ctx := testContext(config, bp, nil)
|
||||
|
||||
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
|
||||
if errs == nil {
|
||||
_, errs = ctx.PrepareBuildActions(config)
|
||||
}
|
||||
if errs == nil && test.err != "" {
|
||||
t.Fatalf("want error %q, got no error", test.err)
|
||||
} else if errs != nil && test.err == "" {
|
||||
android.FailIfErrored(t, errs)
|
||||
} else if test.err != "" {
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("want 1 error, got %d errors:", len(errs))
|
||||
for _, err := range errs {
|
||||
t.Errorf(" %s", err.Error())
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), test.err) {
|
||||
t.Fatalf("want %q, got %q", test.err, errs[0].Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
gen := ctx.ModuleForTests("gen", "").Module().(*Module)
|
||||
if gen.rawCommand != "'"+test.expect+"'" {
|
||||
t.Errorf("want %q, got %q", test.expect, gen.rawCommand)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type testTool struct {
|
||||
android.ModuleBase
|
||||
outputFile android.Path
|
||||
}
|
||||
|
||||
func toolFactory() android.Module {
|
||||
module := &testTool{}
|
||||
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
|
||||
return module
|
||||
}
|
||||
|
||||
func (t *testTool) DepsMutator(ctx android.BottomUpMutatorContext) {}
|
||||
|
||||
func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
t.outputFile = android.PathForTesting("out", ctx.ModuleName())
|
||||
}
|
||||
|
||||
func (t *testTool) HostToolPath() android.OptionalPath {
|
||||
return android.OptionalPathForPath(t.outputFile)
|
||||
}
|
||||
|
||||
var _ HostToolProvider = (*testTool)(nil)
|
Loading…
Reference in a new issue