1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gn/ninja_create_bundle_target_writer.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <sstream>
10
11 #include "gn/target.h"
12 #include "gn/test_with_scope.h"
13 #include "util/test/test.h"
14
15 namespace {
16
SetupBundleDataDir(BundleData * bundle_data,const std::string & root_dir)17 void SetupBundleDataDir(BundleData* bundle_data, const std::string& root_dir) {
18 std::string bundle_root_dir = root_dir + "/bar.bundle";
19 bundle_data->root_dir() = SourceDir(bundle_root_dir);
20 bundle_data->contents_dir() = SourceDir(bundle_root_dir + "/Contents");
21 bundle_data->resources_dir() =
22 SourceDir(bundle_data->contents_dir().value() + "/Resources");
23 bundle_data->executable_dir() =
24 SourceDir(bundle_data->contents_dir().value() + "/MacOS");
25 }
26
NewAction(const TestWithScope & setup)27 std::unique_ptr<Target> NewAction(const TestWithScope& setup) {
28 Err err;
29 auto action = std::make_unique<Target>(setup.settings(),
30 Label(SourceDir("//foo/"), "bar"));
31 action->set_output_type(Target::ACTION);
32 action->visibility().SetPublic();
33 action->action_values().set_script(SourceFile("//foo/script.py"));
34
35 action->action_values().outputs() =
36 SubstitutionList::MakeForTest("//out/Debug/foo.out");
37
38 action->SetToolchain(setup.toolchain());
39 return action;
40 }
41
42 } // namespace
43
44 // Tests multiple files with an output pattern.
TEST(NinjaCreateBundleTargetWriter,Run)45 TEST(NinjaCreateBundleTargetWriter, Run) {
46 Err err;
47 TestWithScope setup;
48
49 std::unique_ptr<Target> action = NewAction(setup);
50 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
51
52 Target bundle_data(setup.settings(), Label(SourceDir("//foo/"), "data"));
53 bundle_data.set_output_type(Target::BUNDLE_DATA);
54 bundle_data.sources().push_back(SourceFile("//foo/input1.txt"));
55 bundle_data.sources().push_back(SourceFile("//foo/input2.txt"));
56 bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
57 "{{bundle_resources_dir}}/{{source_file_part}}");
58 bundle_data.SetToolchain(setup.toolchain());
59 bundle_data.visibility().SetPublic();
60 ASSERT_TRUE(bundle_data.OnResolved(&err));
61
62 Target create_bundle(
63 setup.settings(),
64 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
65 setup.toolchain()->label().name()));
66 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
67 create_bundle.set_output_type(Target::CREATE_BUNDLE);
68 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
69 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
70 create_bundle.SetToolchain(setup.toolchain());
71 ASSERT_TRUE(create_bundle.OnResolved(&err));
72
73 std::ostringstream out;
74 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
75 writer.Run();
76
77 const char expected[] =
78 "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
79 "obj/foo/data.stamp\n"
80 "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
81 "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
82 "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
83 "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
84 "build obj/baz/bar.stamp: stamp "
85 "bar.bundle/Contents/Resources/input1.txt "
86 "bar.bundle/Contents/Resources/input2.txt"
87 " || obj/baz/bar.inputdeps.stamp\n"
88 "build bar.bundle: phony obj/baz/bar.stamp\n";
89 std::string out_str = out.str();
90 EXPECT_EQ(expected, out_str);
91 }
92
93 // Tests creating a bundle in a sub-directory of $root_out_dir.
TEST(NinjaCreateBundleTargetWriter,InSubDirectory)94 TEST(NinjaCreateBundleTargetWriter, InSubDirectory) {
95 Err err;
96 TestWithScope setup;
97
98 std::unique_ptr<Target> action = NewAction(setup);
99 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
100
101 Target bundle_data(setup.settings(), Label(SourceDir("//foo/"), "data"));
102 bundle_data.set_output_type(Target::BUNDLE_DATA);
103 bundle_data.sources().push_back(SourceFile("//foo/input1.txt"));
104 bundle_data.sources().push_back(SourceFile("//foo/input2.txt"));
105 bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
106 "{{bundle_resources_dir}}/{{source_file_part}}");
107 bundle_data.SetToolchain(setup.toolchain());
108 bundle_data.visibility().SetPublic();
109 ASSERT_TRUE(bundle_data.OnResolved(&err));
110
111 Target create_bundle(
112 setup.settings(),
113 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
114 setup.toolchain()->label().name()));
115 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug/gen");
116 create_bundle.set_output_type(Target::CREATE_BUNDLE);
117 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
118 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
119 create_bundle.SetToolchain(setup.toolchain());
120 ASSERT_TRUE(create_bundle.OnResolved(&err));
121
122 std::ostringstream out;
123 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
124 writer.Run();
125
126 const char expected[] =
127 "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
128 "obj/foo/data.stamp\n"
129 "build gen/bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
130 "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
131 "build gen/bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
132 "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
133 "build obj/baz/bar.stamp: stamp "
134 "gen/bar.bundle/Contents/Resources/input1.txt "
135 "gen/bar.bundle/Contents/Resources/input2.txt || "
136 "obj/baz/bar.inputdeps.stamp\n"
137 "build gen/bar.bundle: phony obj/baz/bar.stamp\n";
138 std::string out_str = out.str();
139 EXPECT_EQ(expected, out_str);
140 }
141
142 // Tests empty asset catalog with partial_info_plist property defined.
TEST(NinjaCreateBundleTargetWriter,JustPartialInfoPlist)143 TEST(NinjaCreateBundleTargetWriter, JustPartialInfoPlist) {
144 Err err;
145 TestWithScope setup;
146
147 std::unique_ptr<Target> action = NewAction(setup);
148 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
149
150 Target create_bundle(
151 setup.settings(),
152 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
153 setup.toolchain()->label().name()));
154 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
155 create_bundle.set_output_type(Target::CREATE_BUNDLE);
156 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
157 create_bundle.bundle_data().product_type().assign("com.apple.product-type");
158 create_bundle.bundle_data().set_partial_info_plist(
159 SourceFile("//out/Debug/baz/bar/bar_partial_info.plist"));
160 create_bundle.SetToolchain(setup.toolchain());
161 ASSERT_TRUE(create_bundle.OnResolved(&err));
162
163 std::ostringstream out;
164 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
165 writer.Run();
166
167 const char expected[] =
168 "build baz/bar/bar_partial_info.plist: stamp || obj/foo/bar.stamp\n"
169 "build obj/baz/bar.stamp: stamp "
170 "baz/bar/bar_partial_info.plist || obj/foo/bar.stamp\n"
171 "build bar.bundle: phony obj/baz/bar.stamp\n";
172 std::string out_str = out.str();
173 EXPECT_EQ(expected, out_str);
174 }
175
176 // Tests multiple files from asset catalog.
TEST(NinjaCreateBundleTargetWriter,AssetCatalog)177 TEST(NinjaCreateBundleTargetWriter, AssetCatalog) {
178 Err err;
179 TestWithScope setup;
180
181 std::unique_ptr<Target> action = NewAction(setup);
182 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
183
184 Target bundle_data(setup.settings(), Label(SourceDir("//foo/"), "data"));
185 bundle_data.set_output_type(Target::BUNDLE_DATA);
186 bundle_data.sources().push_back(
187 SourceFile("//foo/Foo.xcassets/Contents.json"));
188 bundle_data.sources().push_back(
189 SourceFile("//foo/Foo.xcassets/foo.colorset/Contents.json"));
190 bundle_data.sources().push_back(
191 SourceFile("//foo/Foo.xcassets/foo.imageset/Contents.json"));
192 bundle_data.sources().push_back(
193 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29.png"));
194 bundle_data.sources().push_back(
195 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@2x.png"));
196 bundle_data.sources().push_back(
197 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@3x.png"));
198 bundle_data.sources().push_back(
199 SourceFile("//foo/Foo.xcassets/foo.dataset/Contents.json"));
200 bundle_data.sources().push_back(
201 SourceFile("//foo/Foo.xcassets/foo.dataset/FooScript.js"));
202 bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
203 "{{bundle_resources_dir}}/{{source_file_part}}");
204 bundle_data.SetToolchain(setup.toolchain());
205 bundle_data.visibility().SetPublic();
206 ASSERT_TRUE(bundle_data.OnResolved(&err));
207
208 Target create_bundle(
209 setup.settings(),
210 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
211 setup.toolchain()->label().name()));
212 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
213 create_bundle.set_output_type(Target::CREATE_BUNDLE);
214 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
215 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
216 create_bundle.bundle_data().product_type().assign("com.apple.product-type");
217 create_bundle.SetToolchain(setup.toolchain());
218 ASSERT_TRUE(create_bundle.OnResolved(&err));
219
220 std::ostringstream out;
221 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
222 writer.Run();
223
224 const char expected[] =
225 "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
226 "obj/foo/data.stamp\n"
227 "build bar.bundle/Contents/Resources/Assets.car: compile_xcassets "
228 "../../foo/Foo.xcassets | obj/foo/data.stamp || "
229 "obj/baz/bar.inputdeps.stamp\n"
230 " product_type = com.apple.product-type\n"
231 "build obj/baz/bar.stamp: stamp "
232 "bar.bundle/Contents/Resources/Assets.car || "
233 "obj/baz/bar.inputdeps.stamp\n"
234 "build bar.bundle: phony obj/baz/bar.stamp\n";
235 std::string out_str = out.str();
236 EXPECT_EQ(expected, out_str);
237 }
238
239 // Tests that the phony target for the top-level bundle directory is generated
240 // correctly.
TEST(NinjaCreateBundleTargetWriter,PhonyTarget)241 TEST(NinjaCreateBundleTargetWriter, PhonyTarget) {
242 Err err;
243 TestWithScope setup;
244
245 Target create_bundle(
246 setup.settings(),
247 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
248 setup.toolchain()->label().name()));
249 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
250 create_bundle.set_output_type(Target::CREATE_BUNDLE);
251 create_bundle.SetToolchain(setup.toolchain());
252 ASSERT_TRUE(create_bundle.OnResolved(&err));
253
254 std::ostringstream out;
255 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
256 writer.Run();
257
258 const char expected[] =
259 "build obj/baz/bar.stamp: stamp\n"
260 "build bar.bundle: phony obj/baz/bar.stamp\n";
261 std::string out_str = out.str();
262 EXPECT_EQ(expected, out_str);
263 }
264
265 // Tests complex target with multiple bundle_data sources, including
266 // some asset catalog.
TEST(NinjaCreateBundleTargetWriter,Complex)267 TEST(NinjaCreateBundleTargetWriter, Complex) {
268 Err err;
269 TestWithScope setup;
270
271 std::unique_ptr<Target> action = NewAction(setup);
272 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
273
274 Target bundle_data0(setup.settings(),
275 Label(SourceDir("//qux/"), "info_plist"));
276 bundle_data0.set_output_type(Target::BUNDLE_DATA);
277 bundle_data0.sources().push_back(SourceFile("//qux/qux-Info.plist"));
278 bundle_data0.action_values().outputs() =
279 SubstitutionList::MakeForTest("{{bundle_contents_dir}}/Info.plist");
280 bundle_data0.SetToolchain(setup.toolchain());
281 bundle_data0.visibility().SetPublic();
282 ASSERT_TRUE(bundle_data0.OnResolved(&err));
283
284 Target bundle_data1(setup.settings(), Label(SourceDir("//foo/"), "data"));
285 bundle_data1.set_output_type(Target::BUNDLE_DATA);
286 bundle_data1.sources().push_back(SourceFile("//foo/input1.txt"));
287 bundle_data1.sources().push_back(SourceFile("//foo/input2.txt"));
288 bundle_data1.action_values().outputs() = SubstitutionList::MakeForTest(
289 "{{bundle_resources_dir}}/{{source_file_part}}");
290 bundle_data1.SetToolchain(setup.toolchain());
291 bundle_data1.visibility().SetPublic();
292 ASSERT_TRUE(bundle_data1.OnResolved(&err));
293
294 Target bundle_data2(setup.settings(), Label(SourceDir("//foo/"), "assets"));
295 bundle_data2.set_output_type(Target::BUNDLE_DATA);
296 bundle_data2.sources().push_back(
297 SourceFile("//foo/Foo.xcassets/Contents.json"));
298 bundle_data2.sources().push_back(
299 SourceFile("//foo/Foo.xcassets/foo.colorset/Contents.json"));
300 bundle_data2.sources().push_back(
301 SourceFile("//foo/Foo.xcassets/foo.imageset/Contents.json"));
302 bundle_data2.sources().push_back(
303 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29.png"));
304 bundle_data2.sources().push_back(
305 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@2x.png"));
306 bundle_data2.sources().push_back(
307 SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@3x.png"));
308 bundle_data2.sources().push_back(
309 SourceFile("//foo/Foo.xcassets/foo.dataset/Contents.json"));
310 bundle_data2.sources().push_back(
311 SourceFile("//foo/Foo.xcassets/foo.dataset/FooScript.js"));
312 bundle_data2.action_values().outputs() = SubstitutionList::MakeForTest(
313 "{{bundle_resources_dir}}/{{source_file_part}}");
314 bundle_data2.SetToolchain(setup.toolchain());
315 bundle_data2.visibility().SetPublic();
316 ASSERT_TRUE(bundle_data2.OnResolved(&err));
317
318 Target bundle_data3(setup.settings(), Label(SourceDir("//quz/"), "assets"));
319 bundle_data3.set_output_type(Target::BUNDLE_DATA);
320 bundle_data3.sources().push_back(
321 SourceFile("//quz/Quz.xcassets/Contents.json"));
322 bundle_data3.sources().push_back(
323 SourceFile("//quz/Quz.xcassets/quz.imageset/Contents.json"));
324 bundle_data3.sources().push_back(
325 SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29.png"));
326 bundle_data3.sources().push_back(
327 SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29@2x.png"));
328 bundle_data3.sources().push_back(
329 SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29@3x.png"));
330 bundle_data3.sources().push_back(
331 SourceFile("//quz/Quz.xcassets/quz.dataset/Contents.json"));
332 bundle_data3.sources().push_back(
333 SourceFile("//quz/Quz.xcassets/quz.dataset/QuzScript.js"));
334 bundle_data3.action_values().outputs() = SubstitutionList::MakeForTest(
335 "{{bundle_resources_dir}}/{{source_file_part}}");
336 bundle_data3.SetToolchain(setup.toolchain());
337 bundle_data3.visibility().SetPublic();
338 ASSERT_TRUE(bundle_data3.OnResolved(&err));
339
340 Target bundle_data4(setup.settings(), Label(SourceDir("//biz/"), "assets"));
341 bundle_data4.set_output_type(Target::BUNDLE_DATA);
342 bundle_data4.sources().push_back(
343 SourceFile("//biz/Biz.xcassets/Contents.json"));
344 bundle_data4.sources().push_back(
345 SourceFile("//biz/Biz.xcassets/biz.colorset/Contents.json"));
346 bundle_data4.action_values().outputs() = SubstitutionList::MakeForTest(
347 "{{bundle_resources_dir}}/{{source_file_part}}");
348 bundle_data4.SetToolchain(setup.toolchain());
349 bundle_data4.visibility().SetPublic();
350 ASSERT_TRUE(bundle_data4.OnResolved(&err));
351
352 Target create_bundle(
353 setup.settings(),
354 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
355 setup.toolchain()->label().name()));
356 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
357 create_bundle.set_output_type(Target::CREATE_BUNDLE);
358 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data0));
359 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data1));
360 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data2));
361 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data3));
362 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data4));
363 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
364 create_bundle.bundle_data().product_type().assign("com.apple.product-type");
365 create_bundle.bundle_data().set_partial_info_plist(
366 SourceFile("//out/Debug/baz/bar/bar_partial_info.plist"));
367 create_bundle.SetToolchain(setup.toolchain());
368 ASSERT_TRUE(create_bundle.OnResolved(&err));
369
370 std::ostringstream out;
371 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
372 writer.Run();
373
374 const char expected[] =
375 "build obj/baz/bar.inputdeps.stamp: stamp obj/biz/assets.stamp "
376 "obj/foo/assets.stamp obj/foo/bar.stamp obj/foo/data.stamp "
377 "obj/qux/info_plist.stamp obj/quz/assets.stamp\n"
378 "build bar.bundle/Contents/Info.plist: copy_bundle_data "
379 "../../qux/qux-Info.plist || obj/baz/bar.inputdeps.stamp\n"
380 "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
381 "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
382 "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
383 "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
384 "build obj/baz/bar.xcassets.inputdeps.stamp: stamp "
385 "obj/foo/assets.stamp "
386 "obj/quz/assets.stamp obj/biz/assets.stamp\n"
387 "build bar.bundle/Contents/Resources/Assets.car | "
388 "baz/bar/bar_partial_info.plist: compile_xcassets "
389 "../../foo/Foo.xcassets ../../quz/Quz.xcassets "
390 "../../biz/Biz.xcassets | obj/baz/bar.xcassets.inputdeps.stamp || "
391 "obj/baz/bar.inputdeps.stamp\n"
392 " product_type = com.apple.product-type\n"
393 " partial_info_plist = baz/bar/bar_partial_info.plist\n"
394 "build obj/baz/bar.stamp: stamp "
395 "bar.bundle/Contents/Info.plist "
396 "bar.bundle/Contents/Resources/input1.txt "
397 "bar.bundle/Contents/Resources/input2.txt "
398 "bar.bundle/Contents/Resources/Assets.car "
399 "baz/bar/bar_partial_info.plist || obj/baz/bar.inputdeps.stamp\n"
400 "build bar.bundle: phony obj/baz/bar.stamp\n";
401 std::string out_str = out.str();
402 EXPECT_EQ(expected, out_str);
403 }
404
405 // Tests code signing steps.
TEST(NinjaCreateBundleTargetWriter,CodeSigning)406 TEST(NinjaCreateBundleTargetWriter, CodeSigning) {
407 Err err;
408 TestWithScope setup;
409
410 std::unique_ptr<Target> action = NewAction(setup);
411 ASSERT_TRUE(action->OnResolved(&err)) << err.message();
412
413 Target executable(setup.settings(), Label(SourceDir("//baz/"), "quz"));
414 executable.set_output_type(Target::EXECUTABLE);
415 executable.sources().push_back(SourceFile("//baz/quz.c"));
416 executable.SetToolchain(setup.toolchain());
417 executable.visibility().SetPublic();
418 ASSERT_TRUE(executable.OnResolved(&err));
419
420 Target bundle_data(setup.settings(), Label(SourceDir("//foo/"), "data"));
421 bundle_data.set_output_type(Target::BUNDLE_DATA);
422 bundle_data.sources().push_back(SourceFile("//foo/input1.txt"));
423 bundle_data.sources().push_back(SourceFile("//foo/input2.txt"));
424 bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
425 "{{bundle_resources_dir}}/{{source_file_part}}");
426 bundle_data.SetToolchain(setup.toolchain());
427 bundle_data.visibility().SetPublic();
428 ASSERT_TRUE(bundle_data.OnResolved(&err));
429
430 Target create_bundle(
431 setup.settings(),
432 Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
433 setup.toolchain()->label().name()));
434 SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
435 create_bundle.set_output_type(Target::CREATE_BUNDLE);
436 create_bundle.bundle_data().set_code_signing_script(
437 SourceFile("//build/codesign.py"));
438 create_bundle.bundle_data().code_signing_sources().push_back(
439 SourceFile("//out/Debug/quz"));
440 create_bundle.bundle_data().code_signing_outputs() =
441 SubstitutionList::MakeForTest(
442 "//out/Debug/bar.bundle/Contents/quz",
443 "//out/Debug/bar.bundle/_CodeSignature/CodeResources");
444 create_bundle.bundle_data().code_signing_args() =
445 SubstitutionList::MakeForTest("-b=quz", "bar.bundle");
446 create_bundle.public_deps().push_back(LabelTargetPair(&executable));
447 create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
448 create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
449 create_bundle.SetToolchain(setup.toolchain());
450 ASSERT_TRUE(create_bundle.OnResolved(&err));
451
452 std::ostringstream out;
453 NinjaCreateBundleTargetWriter writer(&create_bundle, out);
454 writer.Run();
455
456 const char expected[] =
457 "build obj/baz/bar.inputdeps.stamp: stamp ./quz obj/foo/bar.stamp "
458 "obj/foo/data.stamp\n"
459 "rule __baz_bar___toolchain_default__code_signing_rule\n"
460 " command = ../../build/codesign.py -b=quz bar.bundle\n"
461 " description = CODE SIGNING //baz:bar(//toolchain:default)\n"
462 " restat = 1\n"
463 "\n"
464 "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
465 "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
466 "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
467 "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
468 "build obj/baz/bar.codesigning.inputdeps.stamp: stamp "
469 "../../build/codesign.py "
470 "quz "
471 "bar.bundle/Contents/Resources/input1.txt "
472 "bar.bundle/Contents/Resources/input2.txt || "
473 "obj/baz/bar.inputdeps.stamp\n"
474 "build bar.bundle/Contents/quz bar.bundle/_CodeSignature/CodeResources: "
475 "__baz_bar___toolchain_default__code_signing_rule "
476 "| obj/baz/bar.codesigning.inputdeps.stamp\n"
477 "build obj/baz/bar.stamp: stamp "
478 "bar.bundle/Contents/quz "
479 "bar.bundle/_CodeSignature/CodeResources || obj/baz/bar.inputdeps.stamp\n"
480 "build bar.bundle: phony obj/baz/bar.stamp\n";
481 std::string out_str = out.str();
482 EXPECT_EQ(expected, out_str);
483 }
484