| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gn/scheduler.h" | |
| #include "gn/scope.h" | |
| #include "gn/test_with_scheduler.h" | |
| #include "gn/test_with_scope.h" | |
| #include "util/test/test.h" | |
| using FunctionsTarget = TestWithScheduler; | |
| // Checks that we find unused identifiers in targets. | |
| TEST_F(FunctionsTarget, CheckUnused) { | |
| TestWithScope setup; | |
| // The target generator needs a place to put the targets or it will fail. | |
| Scope::ItemVector item_collector; | |
| setup.scope()->set_item_collector(&item_collector); | |
| // Test a good one first. | |
| TestParseInput good_input( | |
| "source_set(\"foo\") {\n" | |
| "}\n"); | |
| ASSERT_FALSE(good_input.has_error()); | |
| Err err; | |
| good_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| // Test a source set with an unused variable. | |
| TestParseInput source_set_input( | |
| "source_set(\"foo\") {\n" | |
| " unused = 5\n" | |
| "}\n"); | |
| ASSERT_FALSE(source_set_input.has_error()); | |
| err = Err(); | |
| source_set_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| } | |
| // Checks that we find uses of identifiers marked as not needed. | |
| TEST_F(FunctionsTarget, CheckNotNeeded) { | |
| TestWithScope setup; | |
| // The target generator needs a place to put the targets or it will fail. | |
| Scope::ItemVector item_collector; | |
| setup.scope()->set_item_collector(&item_collector); | |
| TestParseInput nonscoped_input( | |
| "source_set(\"foo\") {\n" | |
| " a = 1\n" | |
| " not_needed([ \"a\" ])\n" | |
| "}\n"); | |
| ASSERT_FALSE(nonscoped_input.has_error()); | |
| Err err; | |
| nonscoped_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| TestParseInput scoped_input( | |
| "source_set(\"foo\") {\n" | |
| " a = {x = 1 y = 2}\n" | |
| " not_needed(a, \"*\")\n" | |
| "}\n"); | |
| ASSERT_FALSE(scoped_input.has_error()); | |
| err = Err(); | |
| scoped_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| TestParseInput nonexistent_arg_input( | |
| "source_set(\"foo\") {\n" | |
| " a = {x = 1}\n" | |
| " not_needed(a, [ \"x\", \"y\" ])\n" | |
| "}\n"); | |
| ASSERT_FALSE(nonexistent_arg_input.has_error()); | |
| err = Err(); | |
| nonexistent_arg_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| TestParseInput exclusion_input( | |
| "source_set(\"foo\") {\n" | |
| " x = 1\n" | |
| " y = 2\n" | |
| " not_needed(\"*\", [ \"y\" ])\n" | |
| "}\n"); | |
| ASSERT_FALSE(exclusion_input.has_error()); | |
| err = Err(); | |
| exclusion_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()) << err.message(); | |
| EXPECT_EQ("Assignment had no effect.", err.message()); | |
| TestParseInput error_input( | |
| "source_set(\"foo\") {\n" | |
| " a = {x = 1 y = 2}\n" | |
| " not_needed(a, [ \"x \"], [ \"y\" ])\n" | |
| "}\n"); | |
| ASSERT_FALSE(error_input.has_error()); | |
| err = Err(); | |
| error_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| EXPECT_EQ("Not supported with a variable list.", err.message()); | |
| TestParseInput argcount_error_input( | |
| "source_set(\"foo\") {\n" | |
| " not_needed()\n" | |
| "}\n"); | |
| ASSERT_FALSE(argcount_error_input.has_error()); | |
| err = Err(); | |
| argcount_error_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| EXPECT_EQ("Wrong number of arguments.", err.message()); | |
| TestParseInput scope_error_input( | |
| "source_set(\"foo\") {\n" | |
| " a = {x = 1 y = 2}\n" | |
| " not_needed(a)\n" | |
| "}\n"); | |
| ASSERT_FALSE(scope_error_input.has_error()); | |
| err = Err(); | |
| scope_error_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| EXPECT_EQ("Wrong number of arguments.", err.message()); | |
| TestParseInput string_error_input( | |
| "source_set(\"foo\") {\n" | |
| " not_needed(\"*\", {}, \"*\")\n" | |
| "}\n"); | |
| ASSERT_FALSE(string_error_input.has_error()); | |
| err = Err(); | |
| string_error_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| EXPECT_EQ("Wrong number of arguments.", err.message()); | |
| TestParseInput template_input( | |
| R"(# Test that not_needed() propagates through templates correctly; | |
| # no error should arise from not using "a". | |
| template("inner_templ") { | |
| source_set(target_name) { | |
| not_needed(invoker, [ "a" ]) | |
| } | |
| } | |
| template("outer_templ") { | |
| inner_templ(target_name) { | |
| forward_variables_from(invoker, "*") | |
| } | |
| } | |
| outer_templ("foo") { | |
| a = 1 | |
| })"); | |
| ASSERT_FALSE(template_input.has_error()); | |
| err = Err(); | |
| template_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| } | |
| // Checks that the defaults applied to a template invoked by target() use | |
| // the name of the template, rather than the string "target" (which is the | |
| // name of the actual function being called). | |
| TEST_F(FunctionsTarget, TemplateDefaults) { | |
| TestWithScope setup; | |
| // The target generator needs a place to put the targets or it will fail. | |
| Scope::ItemVector item_collector; | |
| setup.scope()->set_item_collector(&item_collector); | |
| // Test a good one first. | |
| TestParseInput good_input( | |
| R"(# Make a template with defaults set. | |
| template("my_templ") { | |
| source_set(target_name) { | |
| forward_variables_from(invoker, "*") | |
| } | |
| } | |
| set_defaults("my_templ") { | |
| default_value = 1 | |
| } | |
| # Invoke the template with target(). This will fail to execute if the | |
| # defaults were not set properly, because "default_value" won't exist. | |
| target("my_templ", "foo") { | |
| print(default_value) | |
| })"); | |
| ASSERT_FALSE(good_input.has_error()); | |
| Err err; | |
| good_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| } | |
| // Checks that we find unused identifiers in targets. | |
| TEST_F(FunctionsTarget, MixedSourceError) { | |
| TestWithScope setup; | |
| // The target generator needs a place to put the targets or it will fail. | |
| Scope::ItemVector item_collector; | |
| setup.scope()->set_item_collector(&item_collector); | |
| // Test a good one first. | |
| TestParseInput good_input( | |
| "source_set(\"foo\") {\n" | |
| " sources = [ \"cpp.cc\", \"rust.rs\" ]" | |
| "}\n"); | |
| ASSERT_FALSE(good_input.has_error()); | |
| Err err; | |
| good_input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_TRUE(err.has_error()); | |
| ASSERT_EQ(err.message(), "More than one language used in target sources."); | |
| } | |
| TEST_F(FunctionsTarget, GroupPublicInputs) { | |
| TestWithScope setup; | |
| Scope::ItemVector item_collector; | |
| setup.scope()->set_item_collector(&item_collector); | |
| TestParseInput input( | |
| R"(group("foo") { | |
| public_inputs = [ "//bar.in" ] | |
| })"); | |
| ASSERT_FALSE(input.has_error()); | |
| Err err; | |
| input.parsed()->Execute(setup.scope(), &err); | |
| ASSERT_SUCCESS(err); | |
| ASSERT_EQ(1u, item_collector.size()); | |
| const Target* target = item_collector[0]->AsTarget(); | |
| ASSERT_TRUE(target); | |
| ASSERT_EQ(1u, target->public_inputs().size()); | |
| EXPECT_EQ("//bar.in", target->public_inputs()[0].value()); | |
| } |