• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.sources().push_back(
203       SourceFile("//foo/Foo.xcassets/file/with/no/known/pattern"));
204   bundle_data.sources().push_back(
205       SourceFile("//foo/Foo.xcassets/nested/bar.xcassets/my/file"));
206   bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
207       "{{bundle_resources_dir}}/{{source_file_part}}");
208   bundle_data.SetToolchain(setup.toolchain());
209   bundle_data.visibility().SetPublic();
210   ASSERT_TRUE(bundle_data.OnResolved(&err));
211 
212   Target create_bundle(
213       setup.settings(),
214       Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
215             setup.toolchain()->label().name()));
216   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
217   create_bundle.set_output_type(Target::CREATE_BUNDLE);
218   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
219   create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
220   create_bundle.bundle_data().product_type().assign("com.apple.product-type");
221   create_bundle.bundle_data().xcasset_compiler_flags() =
222       SubstitutionList::MakeForTest("--app-icon", "foo");
223 
224   create_bundle.SetToolchain(setup.toolchain());
225   ASSERT_TRUE(create_bundle.OnResolved(&err));
226 
227   std::ostringstream out;
228   NinjaCreateBundleTargetWriter writer(&create_bundle, out);
229   writer.Run();
230 
231   const char expected[] =
232       "build obj/baz/bar.inputdeps.stamp: stamp obj/foo/bar.stamp "
233       "obj/foo/data.stamp\n"
234       "build bar.bundle/Contents/Resources/Assets.car: compile_xcassets "
235       "../../foo/Foo.xcassets | obj/foo/data.stamp || "
236       "obj/baz/bar.inputdeps.stamp\n"
237       "  product_type = com.apple.product-type\n"
238       "  xcasset_compiler_flags = --app-icon foo\n"
239       "build obj/baz/bar.stamp: stamp "
240       "bar.bundle/Contents/Resources/Assets.car || "
241       "obj/baz/bar.inputdeps.stamp\n"
242       "build bar.bundle: phony obj/baz/bar.stamp\n";
243   std::string out_str = out.str();
244   EXPECT_EQ(expected, out_str);
245 }
246 
247 // Tests that the phony target for the top-level bundle directory is generated
248 // correctly.
TEST(NinjaCreateBundleTargetWriter,PhonyTarget)249 TEST(NinjaCreateBundleTargetWriter, PhonyTarget) {
250   Err err;
251   TestWithScope setup;
252 
253   Target create_bundle(
254       setup.settings(),
255       Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
256             setup.toolchain()->label().name()));
257   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
258   create_bundle.set_output_type(Target::CREATE_BUNDLE);
259   create_bundle.SetToolchain(setup.toolchain());
260   ASSERT_TRUE(create_bundle.OnResolved(&err));
261 
262   std::ostringstream out;
263   NinjaCreateBundleTargetWriter writer(&create_bundle, out);
264   writer.Run();
265 
266   const char expected[] =
267       "build obj/baz/bar.stamp: stamp\n"
268       "build bar.bundle: phony obj/baz/bar.stamp\n";
269   std::string out_str = out.str();
270   EXPECT_EQ(expected, out_str);
271 }
272 
273 // Tests complex target with multiple bundle_data sources, including
274 // some asset catalog.
TEST(NinjaCreateBundleTargetWriter,Complex)275 TEST(NinjaCreateBundleTargetWriter, Complex) {
276   Err err;
277   TestWithScope setup;
278 
279   std::unique_ptr<Target> action = NewAction(setup);
280   ASSERT_TRUE(action->OnResolved(&err)) << err.message();
281 
282   Target bundle_data0(setup.settings(),
283                       Label(SourceDir("//qux/"), "info_plist"));
284   bundle_data0.set_output_type(Target::BUNDLE_DATA);
285   bundle_data0.sources().push_back(SourceFile("//qux/qux-Info.plist"));
286   bundle_data0.action_values().outputs() =
287       SubstitutionList::MakeForTest("{{bundle_contents_dir}}/Info.plist");
288   bundle_data0.SetToolchain(setup.toolchain());
289   bundle_data0.visibility().SetPublic();
290   ASSERT_TRUE(bundle_data0.OnResolved(&err));
291 
292   Target bundle_data1(setup.settings(), Label(SourceDir("//foo/"), "data"));
293   bundle_data1.set_output_type(Target::BUNDLE_DATA);
294   bundle_data1.sources().push_back(SourceFile("//foo/input1.txt"));
295   bundle_data1.sources().push_back(SourceFile("//foo/input2.txt"));
296   bundle_data1.action_values().outputs() = SubstitutionList::MakeForTest(
297       "{{bundle_resources_dir}}/{{source_file_part}}");
298   bundle_data1.SetToolchain(setup.toolchain());
299   bundle_data1.visibility().SetPublic();
300   ASSERT_TRUE(bundle_data1.OnResolved(&err));
301 
302   Target bundle_data2(setup.settings(), Label(SourceDir("//foo/"), "assets"));
303   bundle_data2.set_output_type(Target::BUNDLE_DATA);
304   bundle_data2.sources().push_back(
305       SourceFile("//foo/Foo.xcassets/Contents.json"));
306   bundle_data2.sources().push_back(
307       SourceFile("//foo/Foo.xcassets/foo.colorset/Contents.json"));
308   bundle_data2.sources().push_back(
309       SourceFile("//foo/Foo.xcassets/foo.imageset/Contents.json"));
310   bundle_data2.sources().push_back(
311       SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29.png"));
312   bundle_data2.sources().push_back(
313       SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@2x.png"));
314   bundle_data2.sources().push_back(
315       SourceFile("//foo/Foo.xcassets/foo.imageset/FooIcon-29@3x.png"));
316   bundle_data2.sources().push_back(
317       SourceFile("//foo/Foo.xcassets/foo.dataset/Contents.json"));
318   bundle_data2.sources().push_back(
319       SourceFile("//foo/Foo.xcassets/foo.dataset/FooScript.js"));
320   bundle_data2.sources().push_back(
321       SourceFile("//foo/Foo.xcassets/file/with/no/known/pattern"));
322   bundle_data2.sources().push_back(
323       SourceFile("//foo/Foo.xcassets/nested/bar.xcassets/my/file"));
324   bundle_data2.action_values().outputs() = SubstitutionList::MakeForTest(
325       "{{bundle_resources_dir}}/{{source_file_part}}");
326   bundle_data2.SetToolchain(setup.toolchain());
327   bundle_data2.visibility().SetPublic();
328   ASSERT_TRUE(bundle_data2.OnResolved(&err));
329 
330   Target bundle_data3(setup.settings(), Label(SourceDir("//quz/"), "assets"));
331   bundle_data3.set_output_type(Target::BUNDLE_DATA);
332   bundle_data3.sources().push_back(
333       SourceFile("//quz/Quz.xcassets/Contents.json"));
334   bundle_data3.sources().push_back(
335       SourceFile("//quz/Quz.xcassets/quz.imageset/Contents.json"));
336   bundle_data3.sources().push_back(
337       SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29.png"));
338   bundle_data3.sources().push_back(
339       SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29@2x.png"));
340   bundle_data3.sources().push_back(
341       SourceFile("//quz/Quz.xcassets/quz.imageset/QuzIcon-29@3x.png"));
342   bundle_data3.sources().push_back(
343       SourceFile("//quz/Quz.xcassets/quz.dataset/Contents.json"));
344   bundle_data3.sources().push_back(
345       SourceFile("//quz/Quz.xcassets/quz.dataset/QuzScript.js"));
346   bundle_data3.action_values().outputs() = SubstitutionList::MakeForTest(
347       "{{bundle_resources_dir}}/{{source_file_part}}");
348   bundle_data3.SetToolchain(setup.toolchain());
349   bundle_data3.visibility().SetPublic();
350   ASSERT_TRUE(bundle_data3.OnResolved(&err));
351 
352   Target bundle_data4(setup.settings(), Label(SourceDir("//biz/"), "assets"));
353   bundle_data4.set_output_type(Target::BUNDLE_DATA);
354   bundle_data4.sources().push_back(
355       SourceFile("//biz/Biz.xcassets/Contents.json"));
356   bundle_data4.sources().push_back(
357       SourceFile("//biz/Biz.xcassets/biz.colorset/Contents.json"));
358   bundle_data4.action_values().outputs() = SubstitutionList::MakeForTest(
359       "{{bundle_resources_dir}}/{{source_file_part}}");
360   bundle_data4.SetToolchain(setup.toolchain());
361   bundle_data4.visibility().SetPublic();
362   ASSERT_TRUE(bundle_data4.OnResolved(&err));
363 
364   Target create_bundle(
365       setup.settings(),
366       Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
367             setup.toolchain()->label().name()));
368   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
369   create_bundle.set_output_type(Target::CREATE_BUNDLE);
370   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data0));
371   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data1));
372   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data2));
373   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data3));
374   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data4));
375   create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
376   create_bundle.bundle_data().product_type().assign("com.apple.product-type");
377   create_bundle.bundle_data().set_partial_info_plist(
378       SourceFile("//out/Debug/baz/bar/bar_partial_info.plist"));
379   create_bundle.SetToolchain(setup.toolchain());
380   ASSERT_TRUE(create_bundle.OnResolved(&err));
381 
382   std::ostringstream out;
383   NinjaCreateBundleTargetWriter writer(&create_bundle, out);
384   writer.Run();
385 
386   const char expected[] =
387       "build obj/baz/bar.inputdeps.stamp: stamp obj/biz/assets.stamp "
388       "obj/foo/assets.stamp obj/foo/bar.stamp obj/foo/data.stamp "
389       "obj/qux/info_plist.stamp obj/quz/assets.stamp\n"
390       "build bar.bundle/Contents/Info.plist: copy_bundle_data "
391       "../../qux/qux-Info.plist || obj/baz/bar.inputdeps.stamp\n"
392       "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
393       "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
394       "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
395       "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
396       "build obj/baz/bar.xcassets.inputdeps.stamp: stamp "
397       "obj/foo/assets.stamp "
398       "obj/quz/assets.stamp obj/biz/assets.stamp\n"
399       "build bar.bundle/Contents/Resources/Assets.car | "
400       "baz/bar/bar_partial_info.plist: compile_xcassets "
401       "../../foo/Foo.xcassets ../../quz/Quz.xcassets "
402       "../../biz/Biz.xcassets | obj/baz/bar.xcassets.inputdeps.stamp || "
403       "obj/baz/bar.inputdeps.stamp\n"
404       "  product_type = com.apple.product-type\n"
405       "  partial_info_plist = baz/bar/bar_partial_info.plist\n"
406       "build obj/baz/bar.stamp: stamp "
407       "bar.bundle/Contents/Info.plist "
408       "bar.bundle/Contents/Resources/input1.txt "
409       "bar.bundle/Contents/Resources/input2.txt "
410       "bar.bundle/Contents/Resources/Assets.car "
411       "baz/bar/bar_partial_info.plist || obj/baz/bar.inputdeps.stamp\n"
412       "build bar.bundle: phony obj/baz/bar.stamp\n";
413   std::string out_str = out.str();
414   EXPECT_EQ(expected, out_str);
415 }
416 
417 // Tests post-processing step.
TEST(NinjaCreateBundleTargetWriter,PostProcessing)418 TEST(NinjaCreateBundleTargetWriter, PostProcessing) {
419   Err err;
420   TestWithScope setup;
421 
422   std::unique_ptr<Target> action = NewAction(setup);
423   ASSERT_TRUE(action->OnResolved(&err)) << err.message();
424 
425   Target executable(setup.settings(), Label(SourceDir("//baz/"), "quz"));
426   executable.set_output_type(Target::EXECUTABLE);
427   executable.sources().push_back(SourceFile("//baz/quz.c"));
428   executable.SetToolchain(setup.toolchain());
429   executable.visibility().SetPublic();
430   ASSERT_TRUE(executable.OnResolved(&err));
431 
432   Target bundle_data(setup.settings(), Label(SourceDir("//foo/"), "data"));
433   bundle_data.set_output_type(Target::BUNDLE_DATA);
434   bundle_data.sources().push_back(SourceFile("//foo/input1.txt"));
435   bundle_data.sources().push_back(SourceFile("//foo/input2.txt"));
436   bundle_data.action_values().outputs() = SubstitutionList::MakeForTest(
437       "{{bundle_resources_dir}}/{{source_file_part}}");
438   bundle_data.SetToolchain(setup.toolchain());
439   bundle_data.visibility().SetPublic();
440   ASSERT_TRUE(bundle_data.OnResolved(&err));
441 
442   Target create_bundle(
443       setup.settings(),
444       Label(SourceDir("//baz/"), "bar", setup.toolchain()->label().dir(),
445             setup.toolchain()->label().name()));
446   SetupBundleDataDir(&create_bundle.bundle_data(), "//out/Debug");
447   create_bundle.set_output_type(Target::CREATE_BUNDLE);
448   create_bundle.bundle_data().set_post_processing_script(
449       SourceFile("//build/codesign.py"));
450   create_bundle.bundle_data().post_processing_sources().push_back(
451       SourceFile("//out/Debug/quz"));
452   create_bundle.bundle_data().post_processing_outputs() =
453       SubstitutionList::MakeForTest(
454           "//out/Debug/bar.bundle/Contents/quz",
455           "//out/Debug/bar.bundle/_CodeSignature/CodeResources");
456   create_bundle.bundle_data().post_processing_args() =
457       SubstitutionList::MakeForTest("-b=quz", "bar.bundle");
458   create_bundle.public_deps().push_back(LabelTargetPair(&executable));
459   create_bundle.private_deps().push_back(LabelTargetPair(&bundle_data));
460   create_bundle.private_deps().push_back(LabelTargetPair(action.get()));
461   create_bundle.SetToolchain(setup.toolchain());
462   ASSERT_TRUE(create_bundle.OnResolved(&err));
463 
464   std::ostringstream out;
465   NinjaCreateBundleTargetWriter writer(&create_bundle, out);
466   writer.Run();
467 
468   const char expected[] =
469       "build obj/baz/bar.inputdeps.stamp: stamp ./quz obj/foo/bar.stamp "
470       "obj/foo/data.stamp\n"
471       "rule __baz_bar___toolchain_default__post_processing_rule\n"
472       "  command =  ../../build/codesign.py -b=quz bar.bundle\n"
473       "  description = POST PROCESSING //baz:bar(//toolchain:default)\n"
474       "  restat = 1\n"
475       "\n"
476       "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data "
477       "../../foo/input1.txt || obj/baz/bar.inputdeps.stamp\n"
478       "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data "
479       "../../foo/input2.txt || obj/baz/bar.inputdeps.stamp\n"
480       "build obj/baz/bar.postprocessing.inputdeps.stamp: stamp "
481       "../../build/codesign.py "
482       "quz "
483       "bar.bundle/Contents/Resources/input1.txt "
484       "bar.bundle/Contents/Resources/input2.txt || "
485       "obj/baz/bar.inputdeps.stamp\n"
486       "build bar.bundle/Contents/quz bar.bundle/_CodeSignature/CodeResources: "
487       "__baz_bar___toolchain_default__post_processing_rule "
488       "| obj/baz/bar.postprocessing.inputdeps.stamp\n"
489       "build obj/baz/bar.stamp: stamp "
490       "bar.bundle/Contents/quz "
491       "bar.bundle/_CodeSignature/CodeResources || obj/baz/bar.inputdeps.stamp\n"
492       "build bar.bundle: phony obj/baz/bar.stamp\n";
493   std::string out_str = out.str();
494   EXPECT_EQ(expected, out_str);
495 }
496