blob: 2f60f82da1c0980e6fa24f2350fb3ba7ca781740 [file] [log] [blame]
// Copyright 2015 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/test_with_scheduler.h"
#include "gn/test_with_scope.h"
#include "util/test/test.h"
using FunctionForwardVariablesFromTest = TestWithScheduler;
TEST_F(FunctionForwardVariablesFromTest, List) {
Err err;
std::string program =
"template(\"a\") {\n"
" forward_variables_from(invoker, [\"x\", \"y\", \"z\"])\n"
" assert(!defined(z))\n" // "z" should still be undefined.
" print(\"$target_name, $x, $y\")\n"
"}\n"
"a(\"target\") {\n"
" x = 1\n"
" y = 2\n"
"}\n";
{
TestWithScope setup;
// Defines a template and copy the two x and y, and z values out.
TestParseInput input(program);
ASSERT_FALSE(input.has_error());
input.parsed()->Execute(setup.scope(), &err);
ASSERT_FALSE(err.has_error()) << err.message();
EXPECT_EQ("target, 1, 2\n", setup.print_output());
setup.print_output().clear();
}
{
TestWithScope setup;
// Test that the same input but forwarding a variable with the name of
// something in the given scope throws an error rather than clobbering it.
// This uses the same known-good program as before, but adds another
// variable in the scope before it.
TestParseInput clobber("x = 1\n" + program);
ASSERT_FALSE(clobber.has_error());
clobber.parsed()->Execute(setup.scope(), &err);
ASSERT_TRUE(err.has_error()); // Should thow a clobber error.
EXPECT_EQ("Clobbering existing value.", err.message());
}
}
TEST_F(FunctionForwardVariablesFromTest, LiteralList) {
TestWithScope setup;
// Forwards all variables from a literal scope into another scope definition.
TestParseInput input(
"a = {\n"
" forward_variables_from({x = 1 y = 2}, \"*\")\n"
" z = 3\n"
"}\n"
"print(\"${a.x} ${a.y} ${a.z}\")\n");
ASSERT_FALSE(input.has_error());
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_FALSE(err.has_error()) << err.message();
EXPECT_EQ("1 2 3\n", setup.print_output());
setup.print_output().clear();
}
TEST_F(FunctionForwardVariablesFromTest, ListWithExclusion) {
TestWithScope setup;
// Defines a template and copy the two x and y, and z values out.
TestParseInput input(
"template(\"a\") {\n"
" forward_variables_from(invoker, [\"x\", \"y\", \"z\"], [\"z\"])\n"
" assert(!defined(z))\n" // "z" should still be undefined.
" print(\"$target_name, $x, $y\")\n"
"}\n"
"a(\"target\") {\n"
" x = 1\n"
" y = 2\n"
" z = 3\n"
" print(\"$z\")\n"
"}\n");
ASSERT_FALSE(input.has_error());
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_FALSE(err.has_error()) << err.message();
EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
setup.print_output().clear();
}
TEST_F(FunctionForwardVariablesFromTest, ErrorCases) {
TestWithScope setup;
// Type check the source scope.
TestParseInput invalid_source(
"template(\"a\") {\n"
" forward_variables_from(42, [\"x\"])\n"
" print(\"$target_name\")\n" // Prevent unused var error.
"}\n"
"a(\"target\") {\n"
"}\n");
ASSERT_FALSE(invalid_source.has_error());
Err err;
invalid_source.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("This is not a scope.", err.message());
// Type check the list. We need to use a new template name each time since
// all of these invocations are executing in sequence in the same scope.
TestParseInput invalid_list(
"template(\"b\") {\n"
" forward_variables_from(invoker, 42)\n"
" print(\"$target_name\")\n"
"}\n"
"b(\"target\") {\n"
"}\n");
ASSERT_FALSE(invalid_list.has_error());
err = Err();
invalid_list.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("Not a valid list of variables to copy.", err.message());
// Type check the exclusion list.
TestParseInput invalid_exclusion_list(
"template(\"c\") {\n"
" forward_variables_from(invoker, \"*\", 42)\n"
" print(\"$target_name\")\n"
"}\n"
"c(\"target\") {\n"
"}\n");
ASSERT_FALSE(invalid_exclusion_list.has_error());
err = Err();
invalid_exclusion_list.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("Not a valid list of variables to exclude.", err.message());
// Programmatic values should error.
TestParseInput prog(
"template(\"d\") {\n"
" forward_variables_from(invoker, [\"root_out_dir\"])\n"
" print(\"$target_name\")\n"
"}\n"
"d(\"target\") {\n"
"}\n");
ASSERT_FALSE(prog.has_error());
err = Err();
prog.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("This value can't be forwarded.", err.message());
// Not enough arguments.
TestParseInput not_enough_arguments(
"template(\"e\") {\n"
" forward_variables_from(invoker)\n"
" print(\"$target_name\")\n"
"}\n"
"e(\"target\") {\n"
"}\n");
ASSERT_FALSE(not_enough_arguments.has_error());
err = Err();
not_enough_arguments.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("Wrong number of arguments.", err.message());
// Too many arguments.
TestParseInput too_many_arguments(
"template(\"f\") {\n"
" forward_variables_from(invoker, \"*\", [], [])\n"
" print(\"$target_name\")\n"
"}\n"
"f(\"target\") {\n"
"}\n");
ASSERT_FALSE(too_many_arguments.has_error());
err = Err();
too_many_arguments.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ("Wrong number of arguments.", err.message());
}
TEST_F(FunctionForwardVariablesFromTest, Star) {
TestWithScope setup;
// Defines a template and copy the two x and y values out. The "*" behavior
// should clobber existing variables with the same name.
TestParseInput input(
"template(\"a\") {\n"
" x = 1000000\n" // Should be clobbered.
" forward_variables_from(invoker, \"*\")\n"
" print(\"$target_name, $x, $y\")\n"
"}\n"
"a(\"target\") {\n"
" x = 1\n"
" y = 2\n"
"}\n");
ASSERT_FALSE(input.has_error());
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_FALSE(err.has_error()) << err.message();
EXPECT_EQ("target, 1, 2\n", setup.print_output());
setup.print_output().clear();
}
TEST_F(FunctionForwardVariablesFromTest, StarWithExclusion) {
TestWithScope setup;
// Defines a template and copy all values except z value. The "*" behavior
// should clobber existing variables with the same name.
TestParseInput input(
"template(\"a\") {\n"
" x = 1000000\n" // Should be clobbered.
" forward_variables_from(invoker, \"*\", [\"z\"])\n"
" print(\"$target_name, $x, $y\")\n"
"}\n"
"a(\"target\") {\n"
" x = 1\n"
" y = 2\n"
" z = 3\n"
" print(\"$z\")\n"
"}\n");
ASSERT_FALSE(input.has_error());
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_FALSE(err.has_error()) << err.message();
EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
setup.print_output().clear();
}