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