1// Copyright 2014 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 <sstream>
6
7#include "testing/gtest/include/gtest/gtest.h"
8#include "tools/gn/ninja_target_writer.h"
9#include "tools/gn/target.h"
10#include "tools/gn/test_with_scope.h"
11
12namespace {
13
14class TestingNinjaTargetWriter : public NinjaTargetWriter {
15 public:
16  TestingNinjaTargetWriter(const Target* target,
17                           const Toolchain* toolchain,
18                           std::ostream& out)
19      : NinjaTargetWriter(target, out) {
20  }
21
22  virtual void Run() OVERRIDE {}
23
24  // Make this public so the test can call it.
25  OutputFile WriteInputDepsStampAndGetDep(
26      const std::vector<const Target*>& extra_hard_deps) {
27    return NinjaTargetWriter::WriteInputDepsStampAndGetDep(extra_hard_deps);
28  }
29};
30
31}  // namespace
32
33TEST(NinjaTargetWriter, WriteInputDepsStampAndGetDep) {
34  TestWithScope setup;
35  Err err;
36
37  // Make a base target that's a hard dep (action).
38  Target base_target(setup.settings(), Label(SourceDir("//foo/"), "base"));
39  base_target.set_output_type(Target::ACTION);
40  base_target.visibility().SetPublic();
41  base_target.SetToolchain(setup.toolchain());
42  base_target.action_values().set_script(SourceFile("//foo/script.py"));
43
44  // Dependent target that also includes a source prerequisite (should get
45  // included) and a source (should not be included).
46  Target target(setup.settings(), Label(SourceDir("//foo/"), "target"));
47  target.set_output_type(Target::EXECUTABLE);
48  target.visibility().SetPublic();
49  target.SetToolchain(setup.toolchain());
50  target.inputs().push_back(SourceFile("//foo/input.txt"));
51  target.sources().push_back(SourceFile("//foo/source.txt"));
52  target.public_deps().push_back(LabelTargetPair(&base_target));
53
54  // Dependent action to test that action sources will be treated the same as
55  // inputs.
56  Target action(setup.settings(), Label(SourceDir("//foo/"), "action"));
57  action.set_output_type(Target::ACTION);
58  action.visibility().SetPublic();
59  action.SetToolchain(setup.toolchain());
60  action.action_values().set_script(SourceFile("//foo/script.py"));
61  action.sources().push_back(SourceFile("//foo/action_source.txt"));
62  action.public_deps().push_back(LabelTargetPair(&target));
63
64  ASSERT_TRUE(base_target.OnResolved(&err));
65  ASSERT_TRUE(target.OnResolved(&err));
66  ASSERT_TRUE(action.OnResolved(&err));
67
68  // Input deps for the base (should be only the script itself).
69  {
70    std::ostringstream stream;
71    TestingNinjaTargetWriter writer(&base_target, setup.toolchain(), stream);
72    OutputFile dep =
73        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>());
74
75    EXPECT_EQ("obj/foo/base.inputdeps.stamp", dep.value());
76    EXPECT_EQ("build obj/foo/base.inputdeps.stamp: stamp "
77                  "../../foo/script.py\n",
78              stream.str());
79  }
80
81  // Input deps for the target (should depend on the base).
82  {
83    std::ostringstream stream;
84    TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream);
85    OutputFile dep =
86        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>());
87
88    EXPECT_EQ("obj/foo/target.inputdeps.stamp", dep.value());
89    EXPECT_EQ("build obj/foo/target.inputdeps.stamp: stamp "
90                  "../../foo/input.txt obj/foo/base.stamp\n",
91              stream.str());
92  }
93
94  // Input deps for action which should depend on the base since its a hard dep
95  // that is a (indirect) dependency, as well as the the action source.
96  {
97    std::ostringstream stream;
98    TestingNinjaTargetWriter writer(&action, setup.toolchain(), stream);
99    OutputFile dep =
100        writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>());
101
102    EXPECT_EQ("obj/foo/action.inputdeps.stamp", dep.value());
103    EXPECT_EQ("build obj/foo/action.inputdeps.stamp: stamp ../../foo/script.py "
104                  "../../foo/action_source.txt obj/foo/base.stamp\n",
105              stream.str());
106  }
107}
108
109// Tests WriteInputDepsStampAndGetDep when toolchain deps are present.
110TEST(NinjaTargetWriter, WriteInputDepsStampAndGetDepWithToolchainDeps) {
111  TestWithScope setup;
112  Err err;
113
114  // Toolchain dependency. Here we make a target in the same toolchain for
115  // simplicity, but in real life (using the Builder) this would be rejected
116  // because it would be a circular dependency (the target depends on its
117  // toolchain, and the toolchain depends on this target).
118  Target toolchain_dep_target(setup.settings(),
119                              Label(SourceDir("//foo/"), "setup"));
120  toolchain_dep_target.set_output_type(Target::ACTION);
121  toolchain_dep_target.SetToolchain(setup.toolchain());
122  ASSERT_TRUE(toolchain_dep_target.OnResolved(&err));
123  setup.toolchain()->deps().push_back(LabelTargetPair(&toolchain_dep_target));
124
125  // Make a binary target
126  Target target(setup.settings(), Label(SourceDir("//foo/"), "target"));
127  target.set_output_type(Target::EXECUTABLE);
128  target.SetToolchain(setup.toolchain());
129  ASSERT_TRUE(target.OnResolved(&err));
130
131  std::ostringstream stream;
132  TestingNinjaTargetWriter writer(&target, setup.toolchain(), stream);
133  OutputFile dep =
134      writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>());
135
136  EXPECT_EQ("obj/foo/target.inputdeps.stamp", dep.value());
137  EXPECT_EQ("build obj/foo/target.inputdeps.stamp: stamp "
138                "obj/foo/setup.stamp\n",
139            stream.str());
140}
141