genrule_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. // Copyright 2018 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package genrule
  15. import (
  16. "io/ioutil"
  17. "os"
  18. "reflect"
  19. "strings"
  20. "testing"
  21. "android/soong/android"
  22. "github.com/google/blueprint/proptools"
  23. )
  24. var buildDir string
  25. func setUp() {
  26. var err error
  27. buildDir, err = ioutil.TempDir("", "genrule_test")
  28. if err != nil {
  29. panic(err)
  30. }
  31. }
  32. func tearDown() {
  33. os.RemoveAll(buildDir)
  34. }
  35. func TestMain(m *testing.M) {
  36. run := func() int {
  37. setUp()
  38. defer tearDown()
  39. return m.Run()
  40. }
  41. os.Exit(run())
  42. }
  43. func testContext(config android.Config) *android.TestContext {
  44. ctx := android.NewTestArchContext()
  45. ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
  46. ctx.RegisterModuleType("tool", toolFactory)
  47. registerGenruleBuildComponents(ctx)
  48. ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
  49. ctx.Register(config)
  50. return ctx
  51. }
  52. func testConfig(bp string, fs map[string][]byte) android.Config {
  53. bp += `
  54. tool {
  55. name: "tool",
  56. }
  57. filegroup {
  58. name: "tool_files",
  59. srcs: [
  60. "tool_file1",
  61. "tool_file2",
  62. ],
  63. }
  64. filegroup {
  65. name: "1tool_file",
  66. srcs: [
  67. "tool_file1",
  68. ],
  69. }
  70. filegroup {
  71. name: "ins",
  72. srcs: [
  73. "in1",
  74. "in2",
  75. ],
  76. }
  77. filegroup {
  78. name: "1in",
  79. srcs: [
  80. "in1",
  81. ],
  82. }
  83. filegroup {
  84. name: "empty",
  85. }
  86. `
  87. mockFS := map[string][]byte{
  88. "tool": nil,
  89. "tool_file1": nil,
  90. "tool_file2": nil,
  91. "in1": nil,
  92. "in2": nil,
  93. "in1.txt": nil,
  94. "in2.txt": nil,
  95. "in3.txt": nil,
  96. }
  97. for k, v := range fs {
  98. mockFS[k] = v
  99. }
  100. return android.TestArchConfig(buildDir, nil, bp, mockFS)
  101. }
  102. func TestGenruleCmd(t *testing.T) {
  103. testcases := []struct {
  104. name string
  105. prop string
  106. allowMissingDependencies bool
  107. err string
  108. expect string
  109. }{
  110. {
  111. name: "empty location tool",
  112. prop: `
  113. tools: ["tool"],
  114. out: ["out"],
  115. cmd: "$(location) > $(out)",
  116. `,
  117. expect: "out/tool > __SBOX_OUT_FILES__",
  118. },
  119. {
  120. name: "empty location tool2",
  121. prop: `
  122. tools: [":tool"],
  123. out: ["out"],
  124. cmd: "$(location) > $(out)",
  125. `,
  126. expect: "out/tool > __SBOX_OUT_FILES__",
  127. },
  128. {
  129. name: "empty location tool file",
  130. prop: `
  131. tool_files: ["tool_file1"],
  132. out: ["out"],
  133. cmd: "$(location) > $(out)",
  134. `,
  135. expect: "tool_file1 > __SBOX_OUT_FILES__",
  136. },
  137. {
  138. name: "empty location tool file fg",
  139. prop: `
  140. tool_files: [":1tool_file"],
  141. out: ["out"],
  142. cmd: "$(location) > $(out)",
  143. `,
  144. expect: "tool_file1 > __SBOX_OUT_FILES__",
  145. },
  146. {
  147. name: "empty location tool and tool file",
  148. prop: `
  149. tools: ["tool"],
  150. tool_files: ["tool_file1"],
  151. out: ["out"],
  152. cmd: "$(location) > $(out)",
  153. `,
  154. expect: "out/tool > __SBOX_OUT_FILES__",
  155. },
  156. {
  157. name: "tool",
  158. prop: `
  159. tools: ["tool"],
  160. out: ["out"],
  161. cmd: "$(location tool) > $(out)",
  162. `,
  163. expect: "out/tool > __SBOX_OUT_FILES__",
  164. },
  165. {
  166. name: "tool2",
  167. prop: `
  168. tools: [":tool"],
  169. out: ["out"],
  170. cmd: "$(location :tool) > $(out)",
  171. `,
  172. expect: "out/tool > __SBOX_OUT_FILES__",
  173. },
  174. {
  175. name: "tool file",
  176. prop: `
  177. tool_files: ["tool_file1"],
  178. out: ["out"],
  179. cmd: "$(location tool_file1) > $(out)",
  180. `,
  181. expect: "tool_file1 > __SBOX_OUT_FILES__",
  182. },
  183. {
  184. name: "tool file fg",
  185. prop: `
  186. tool_files: [":1tool_file"],
  187. out: ["out"],
  188. cmd: "$(location :1tool_file) > $(out)",
  189. `,
  190. expect: "tool_file1 > __SBOX_OUT_FILES__",
  191. },
  192. {
  193. name: "tool files",
  194. prop: `
  195. tool_files: [":tool_files"],
  196. out: ["out"],
  197. cmd: "$(locations :tool_files) > $(out)",
  198. `,
  199. expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
  200. },
  201. {
  202. name: "in1",
  203. prop: `
  204. srcs: ["in1"],
  205. out: ["out"],
  206. cmd: "cat $(in) > $(out)",
  207. `,
  208. expect: "cat ${in} > __SBOX_OUT_FILES__",
  209. },
  210. {
  211. name: "in1 fg",
  212. prop: `
  213. srcs: [":1in"],
  214. out: ["out"],
  215. cmd: "cat $(in) > $(out)",
  216. `,
  217. expect: "cat ${in} > __SBOX_OUT_FILES__",
  218. },
  219. {
  220. name: "ins",
  221. prop: `
  222. srcs: ["in1", "in2"],
  223. out: ["out"],
  224. cmd: "cat $(in) > $(out)",
  225. `,
  226. expect: "cat ${in} > __SBOX_OUT_FILES__",
  227. },
  228. {
  229. name: "ins fg",
  230. prop: `
  231. srcs: [":ins"],
  232. out: ["out"],
  233. cmd: "cat $(in) > $(out)",
  234. `,
  235. expect: "cat ${in} > __SBOX_OUT_FILES__",
  236. },
  237. {
  238. name: "location in1",
  239. prop: `
  240. srcs: ["in1"],
  241. out: ["out"],
  242. cmd: "cat $(location in1) > $(out)",
  243. `,
  244. expect: "cat in1 > __SBOX_OUT_FILES__",
  245. },
  246. {
  247. name: "location in1 fg",
  248. prop: `
  249. srcs: [":1in"],
  250. out: ["out"],
  251. cmd: "cat $(location :1in) > $(out)",
  252. `,
  253. expect: "cat in1 > __SBOX_OUT_FILES__",
  254. },
  255. {
  256. name: "location ins",
  257. prop: `
  258. srcs: ["in1", "in2"],
  259. out: ["out"],
  260. cmd: "cat $(location in1) > $(out)",
  261. `,
  262. expect: "cat in1 > __SBOX_OUT_FILES__",
  263. },
  264. {
  265. name: "location ins fg",
  266. prop: `
  267. srcs: [":ins"],
  268. out: ["out"],
  269. cmd: "cat $(locations :ins) > $(out)",
  270. `,
  271. expect: "cat in1 in2 > __SBOX_OUT_FILES__",
  272. },
  273. {
  274. name: "outs",
  275. prop: `
  276. out: ["out", "out2"],
  277. cmd: "echo foo > $(out)",
  278. `,
  279. expect: "echo foo > __SBOX_OUT_FILES__",
  280. },
  281. {
  282. name: "location out",
  283. prop: `
  284. out: ["out", "out2"],
  285. cmd: "echo foo > $(location out2)",
  286. `,
  287. expect: "echo foo > __SBOX_OUT_DIR__/out2",
  288. },
  289. {
  290. name: "depfile",
  291. prop: `
  292. out: ["out"],
  293. depfile: true,
  294. cmd: "echo foo > $(out) && touch $(depfile)",
  295. `,
  296. expect: "echo foo > __SBOX_OUT_FILES__ && touch __SBOX_DEPFILE__",
  297. },
  298. {
  299. name: "gendir",
  300. prop: `
  301. out: ["out"],
  302. cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
  303. `,
  304. expect: "echo foo > __SBOX_OUT_DIR__/foo && cp __SBOX_OUT_DIR__/foo __SBOX_OUT_FILES__",
  305. },
  306. {
  307. name: "error empty location",
  308. prop: `
  309. out: ["out"],
  310. cmd: "$(location) > $(out)",
  311. `,
  312. err: "at least one `tools` or `tool_files` is required if $(location) is used",
  313. },
  314. {
  315. name: "error empty location no files",
  316. prop: `
  317. tool_files: [":empty"],
  318. out: ["out"],
  319. cmd: "$(location) > $(out)",
  320. `,
  321. err: `default label ":empty" has no files`,
  322. },
  323. {
  324. name: "error empty location multiple files",
  325. prop: `
  326. tool_files: [":tool_files"],
  327. out: ["out"],
  328. cmd: "$(location) > $(out)",
  329. `,
  330. err: `default label ":tool_files" has multiple files`,
  331. },
  332. {
  333. name: "error location",
  334. prop: `
  335. out: ["out"],
  336. cmd: "echo foo > $(location missing)",
  337. `,
  338. err: `unknown location label "missing"`,
  339. },
  340. {
  341. name: "error locations",
  342. prop: `
  343. out: ["out"],
  344. cmd: "echo foo > $(locations missing)",
  345. `,
  346. err: `unknown locations label "missing"`,
  347. },
  348. {
  349. name: "error location no files",
  350. prop: `
  351. out: ["out"],
  352. srcs: [":empty"],
  353. cmd: "echo $(location :empty) > $(out)",
  354. `,
  355. err: `label ":empty" has no files`,
  356. },
  357. {
  358. name: "error locations no files",
  359. prop: `
  360. out: ["out"],
  361. srcs: [":empty"],
  362. cmd: "echo $(locations :empty) > $(out)",
  363. `,
  364. err: `label ":empty" has no files`,
  365. },
  366. {
  367. name: "error location multiple files",
  368. prop: `
  369. out: ["out"],
  370. srcs: [":ins"],
  371. cmd: "echo $(location :ins) > $(out)",
  372. `,
  373. err: `label ":ins" has multiple files`,
  374. },
  375. {
  376. name: "error variable",
  377. prop: `
  378. out: ["out"],
  379. srcs: ["in1"],
  380. cmd: "echo $(foo) > $(out)",
  381. `,
  382. err: `unknown variable '$(foo)'`,
  383. },
  384. {
  385. name: "error depfile",
  386. prop: `
  387. out: ["out"],
  388. cmd: "echo foo > $(out) && touch $(depfile)",
  389. `,
  390. err: "$(depfile) used without depfile property",
  391. },
  392. {
  393. name: "error no depfile",
  394. prop: `
  395. out: ["out"],
  396. depfile: true,
  397. cmd: "echo foo > $(out)",
  398. `,
  399. err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
  400. },
  401. {
  402. name: "error no out",
  403. prop: `
  404. cmd: "echo foo > $(out)",
  405. `,
  406. err: "must have at least one output file",
  407. },
  408. {
  409. name: "srcs allow missing dependencies",
  410. prop: `
  411. srcs: [":missing"],
  412. out: ["out"],
  413. cmd: "cat $(location :missing) > $(out)",
  414. `,
  415. allowMissingDependencies: true,
  416. expect: "cat ***missing srcs :missing*** > __SBOX_OUT_FILES__",
  417. },
  418. {
  419. name: "tool allow missing dependencies",
  420. prop: `
  421. tools: [":missing"],
  422. out: ["out"],
  423. cmd: "$(location :missing) > $(out)",
  424. `,
  425. allowMissingDependencies: true,
  426. expect: "***missing tool :missing*** > __SBOX_OUT_FILES__",
  427. },
  428. }
  429. for _, test := range testcases {
  430. t.Run(test.name, func(t *testing.T) {
  431. bp := "genrule {\n"
  432. bp += "name: \"gen\",\n"
  433. bp += test.prop
  434. bp += "}\n"
  435. config := testConfig(bp, nil)
  436. config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
  437. ctx := testContext(config)
  438. ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
  439. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  440. if errs == nil {
  441. _, errs = ctx.PrepareBuildActions(config)
  442. }
  443. if errs == nil && test.err != "" {
  444. t.Fatalf("want error %q, got no error", test.err)
  445. } else if errs != nil && test.err == "" {
  446. android.FailIfErrored(t, errs)
  447. } else if test.err != "" {
  448. if len(errs) != 1 {
  449. t.Errorf("want 1 error, got %d errors:", len(errs))
  450. for _, err := range errs {
  451. t.Errorf(" %s", err.Error())
  452. }
  453. t.FailNow()
  454. }
  455. if !strings.Contains(errs[0].Error(), test.err) {
  456. t.Fatalf("want %q, got %q", test.err, errs[0].Error())
  457. }
  458. return
  459. }
  460. gen := ctx.ModuleForTests("gen", "").Module().(*Module)
  461. if g, w := gen.rawCommands[0], "'"+test.expect+"'"; w != g {
  462. t.Errorf("want %q, got %q", w, g)
  463. }
  464. })
  465. }
  466. }
  467. func TestGenruleHashInputs(t *testing.T) {
  468. // The basic idea here is to verify that the sbox command (which is
  469. // in the Command field of the generate rule) contains a hash of the
  470. // inputs, but only if $(in) is not referenced in the genrule cmd
  471. // property.
  472. // By including a hash of the inputs, we cause the rule to re-run if
  473. // the list of inputs changes (because the sbox command changes).
  474. // However, if the genrule cmd property already contains $(in), then
  475. // the dependency is already expressed, so we don't need to include the
  476. // hash in that case.
  477. bp := `
  478. genrule {
  479. name: "hash0",
  480. srcs: ["in1.txt", "in2.txt"],
  481. out: ["out"],
  482. cmd: "echo foo > $(out)",
  483. }
  484. genrule {
  485. name: "hash1",
  486. srcs: ["*.txt"],
  487. out: ["out"],
  488. cmd: "echo bar > $(out)",
  489. }
  490. genrule {
  491. name: "hash2",
  492. srcs: ["*.txt"],
  493. out: ["out"],
  494. cmd: "echo $(in) > $(out)",
  495. }
  496. `
  497. testcases := []struct {
  498. name string
  499. expectedHash string
  500. }{
  501. {
  502. name: "hash0",
  503. // sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
  504. expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
  505. },
  506. {
  507. name: "hash1",
  508. // sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
  509. expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
  510. },
  511. {
  512. name: "hash2",
  513. // $(in) is present, option should not appear
  514. expectedHash: "",
  515. },
  516. }
  517. config := testConfig(bp, nil)
  518. ctx := testContext(config)
  519. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  520. if errs == nil {
  521. _, errs = ctx.PrepareBuildActions(config)
  522. }
  523. if errs != nil {
  524. t.Fatal(errs)
  525. }
  526. for _, test := range testcases {
  527. t.Run(test.name, func(t *testing.T) {
  528. gen := ctx.ModuleForTests(test.name, "")
  529. command := gen.Rule("generator").RuleParams.Command
  530. if len(test.expectedHash) > 0 {
  531. // We add spaces before and after to make sure that
  532. // this option doesn't abutt another sbox option.
  533. expectedInputHashOption := " --input-hash " + test.expectedHash + " "
  534. if !strings.Contains(command, expectedInputHashOption) {
  535. t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
  536. }
  537. } else {
  538. if strings.Contains(command, "--input-hash") {
  539. t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
  540. }
  541. }
  542. })
  543. }
  544. }
  545. func TestGenSrcs(t *testing.T) {
  546. testcases := []struct {
  547. name string
  548. prop string
  549. allowMissingDependencies bool
  550. err string
  551. cmds []string
  552. deps []string
  553. files []string
  554. }{
  555. {
  556. name: "gensrcs",
  557. prop: `
  558. tools: ["tool"],
  559. srcs: ["in1.txt", "in2.txt"],
  560. cmd: "$(location) $(in) > $(out)",
  561. `,
  562. cmds: []string{
  563. "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
  564. },
  565. deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
  566. files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
  567. },
  568. {
  569. name: "shards",
  570. prop: `
  571. tools: ["tool"],
  572. srcs: ["in1.txt", "in2.txt", "in3.txt"],
  573. cmd: "$(location) $(in) > $(out)",
  574. shard_size: 2,
  575. `,
  576. cmds: []string{
  577. "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
  578. "'bash -c '\\''out/tool in3.txt > __SBOX_OUT_DIR__/in3.h'\\'''",
  579. },
  580. deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
  581. files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
  582. },
  583. }
  584. for _, test := range testcases {
  585. t.Run(test.name, func(t *testing.T) {
  586. bp := "gensrcs {\n"
  587. bp += `name: "gen",` + "\n"
  588. bp += `output_extension: "h",` + "\n"
  589. bp += test.prop
  590. bp += "}\n"
  591. config := testConfig(bp, nil)
  592. ctx := testContext(config)
  593. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  594. if errs == nil {
  595. _, errs = ctx.PrepareBuildActions(config)
  596. }
  597. if errs == nil && test.err != "" {
  598. t.Fatalf("want error %q, got no error", test.err)
  599. } else if errs != nil && test.err == "" {
  600. android.FailIfErrored(t, errs)
  601. } else if test.err != "" {
  602. if len(errs) != 1 {
  603. t.Errorf("want 1 error, got %d errors:", len(errs))
  604. for _, err := range errs {
  605. t.Errorf(" %s", err.Error())
  606. }
  607. t.FailNow()
  608. }
  609. if !strings.Contains(errs[0].Error(), test.err) {
  610. t.Fatalf("want %q, got %q", test.err, errs[0].Error())
  611. }
  612. return
  613. }
  614. gen := ctx.ModuleForTests("gen", "").Module().(*Module)
  615. if g, w := gen.rawCommands, test.cmds; !reflect.DeepEqual(w, g) {
  616. t.Errorf("want %q, got %q", w, g)
  617. }
  618. if g, w := gen.outputDeps.Strings(), test.deps; !reflect.DeepEqual(w, g) {
  619. t.Errorf("want deps %q, got %q", w, g)
  620. }
  621. if g, w := gen.outputFiles.Strings(), test.files; !reflect.DeepEqual(w, g) {
  622. t.Errorf("want files %q, got %q", w, g)
  623. }
  624. })
  625. }
  626. }
  627. func TestGenruleDefaults(t *testing.T) {
  628. bp := `
  629. genrule_defaults {
  630. name: "gen_defaults1",
  631. cmd: "cp $(in) $(out)",
  632. }
  633. genrule_defaults {
  634. name: "gen_defaults2",
  635. srcs: ["in1"],
  636. }
  637. genrule {
  638. name: "gen",
  639. out: ["out"],
  640. defaults: ["gen_defaults1", "gen_defaults2"],
  641. }
  642. `
  643. config := testConfig(bp, nil)
  644. ctx := testContext(config)
  645. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  646. if errs == nil {
  647. _, errs = ctx.PrepareBuildActions(config)
  648. }
  649. if errs != nil {
  650. t.Fatal(errs)
  651. }
  652. gen := ctx.ModuleForTests("gen", "").Module().(*Module)
  653. expectedCmd := "'cp ${in} __SBOX_OUT_FILES__'"
  654. if gen.rawCommands[0] != expectedCmd {
  655. t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommands[0])
  656. }
  657. expectedSrcs := []string{"in1"}
  658. if !reflect.DeepEqual(expectedSrcs, gen.properties.Srcs) {
  659. t.Errorf("Expected srcs: %q, actual: %q", expectedSrcs, gen.properties.Srcs)
  660. }
  661. }
  662. func TestGenruleWithBazel(t *testing.T) {
  663. bp := `
  664. genrule {
  665. name: "foo",
  666. out: ["one.txt", "two.txt"],
  667. bazel_module: "//foo/bar:bar",
  668. }
  669. `
  670. config := testConfig(bp, nil)
  671. config.BazelContext = android.MockBazelContext{
  672. AllFiles: map[string][]string{
  673. "//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
  674. ctx := testContext(config)
  675. _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
  676. if errs == nil {
  677. _, errs = ctx.PrepareBuildActions(config)
  678. }
  679. if errs != nil {
  680. t.Fatal(errs)
  681. }
  682. gen := ctx.ModuleForTests("foo", "").Module().(*Module)
  683. expectedOutputFiles := []string{"bazelone.txt", "bazeltwo.txt"}
  684. if !reflect.DeepEqual(gen.outputFiles.Strings(), expectedOutputFiles) {
  685. t.Errorf("Expected output files: %q, actual: %q", expectedOutputFiles, gen.outputFiles)
  686. }
  687. if !reflect.DeepEqual(gen.outputDeps.Strings(), expectedOutputFiles) {
  688. t.Errorf("Expected output deps: %q, actual: %q", expectedOutputFiles, gen.outputDeps)
  689. }
  690. }
  691. type testTool struct {
  692. android.ModuleBase
  693. outputFile android.Path
  694. }
  695. func toolFactory() android.Module {
  696. module := &testTool{}
  697. android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
  698. return module
  699. }
  700. func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  701. t.outputFile = android.PathForTesting("out", ctx.ModuleName())
  702. }
  703. func (t *testTool) HostToolPath() android.OptionalPath {
  704. return android.OptionalPathForPath(t.outputFile)
  705. }
  706. var _ android.HostToolProvider = (*testTool)(nil)