Home | History | Annotate | Download | only in gn
      1 // Copyright (c) 2013 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 "testing/gtest/include/gtest/gtest.h"
      6 #include "tools/gn/input_file.h"
      7 #include "tools/gn/parse_tree.h"
      8 #include "tools/gn/scope.h"
      9 #include "tools/gn/test_with_scope.h"
     10 
     11 namespace {
     12 
     13 bool HasStringValueEqualTo(const Scope* scope,
     14                            const char* name,
     15                            const char* expected_value) {
     16   const Value* value = scope->GetValue(name);
     17   if (!value)
     18     return false;
     19   if (value->type() != Value::STRING)
     20     return false;
     21   return value->string_value() == expected_value;
     22 }
     23 
     24 }  // namespace
     25 
     26 TEST(Scope, NonRecursiveMergeTo) {
     27   TestWithScope setup;
     28 
     29   // Make a pretend parse node with proper tracking that we can blame for the
     30   // given value.
     31   InputFile input_file(SourceFile("//foo"));
     32   Token assignment_token(Location(&input_file, 1, 1), Token::STRING,
     33       "\"hello\"");
     34   LiteralNode assignment;
     35   assignment.set_value(assignment_token);
     36 
     37   Value old_value(&assignment, "hello");
     38   setup.scope()->SetValue("v", old_value, &assignment);
     39   base::StringPiece private_var_name("_private");
     40   setup.scope()->SetValue(private_var_name, old_value, &assignment);
     41 
     42   // Detect collisions of values' values.
     43   {
     44     Scope new_scope(setup.settings());
     45     Value new_value(&assignment, "goodbye");
     46     new_scope.SetValue("v", new_value, &assignment);
     47 
     48     Err err;
     49     EXPECT_FALSE(setup.scope()->NonRecursiveMergeTo(
     50         &new_scope, Scope::MergeOptions(),
     51         &assignment, "error", &err));
     52     EXPECT_TRUE(err.has_error());
     53   }
     54 
     55   // The clobber flag should just overwrite colliding values.
     56   {
     57     Scope new_scope(setup.settings());
     58     Value new_value(&assignment, "goodbye");
     59     new_scope.SetValue("v", new_value, &assignment);
     60 
     61     Err err;
     62     Scope::MergeOptions options;
     63     options.clobber_existing = true;
     64     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
     65         &new_scope, options, &assignment, "error", &err));
     66     EXPECT_FALSE(err.has_error());
     67 
     68     const Value* found_value = new_scope.GetValue("v");
     69     ASSERT_TRUE(found_value);
     70     EXPECT_TRUE(old_value == *found_value);
     71   }
     72 
     73   // Don't flag values that technically collide but have the same value.
     74   {
     75     Scope new_scope(setup.settings());
     76     Value new_value(&assignment, "hello");
     77     new_scope.SetValue("v", new_value, &assignment);
     78 
     79     Err err;
     80     Scope::MergeOptions options;
     81     options.clobber_existing = true;
     82     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
     83         &new_scope, options, &assignment, "error", &err));
     84     EXPECT_FALSE(err.has_error());
     85   }
     86 
     87   // Copy private values.
     88   {
     89     Scope new_scope(setup.settings());
     90 
     91     Err err;
     92     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
     93         &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
     94     EXPECT_FALSE(err.has_error());
     95     EXPECT_TRUE(new_scope.GetValue(private_var_name));
     96   }
     97 
     98   // Skip private values.
     99   {
    100     Scope new_scope(setup.settings());
    101 
    102     Err err;
    103     Scope::MergeOptions options;
    104     options.skip_private_vars = true;
    105     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
    106         &new_scope, options, &assignment, "error", &err));
    107     EXPECT_FALSE(err.has_error());
    108     EXPECT_FALSE(new_scope.GetValue(private_var_name));
    109   }
    110 
    111   // Don't mark used.
    112   {
    113     Scope new_scope(setup.settings());
    114 
    115     Err err;
    116     Scope::MergeOptions options;
    117     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
    118         &new_scope, options, &assignment, "error", &err));
    119     EXPECT_FALSE(err.has_error());
    120     EXPECT_FALSE(new_scope.CheckForUnusedVars(&err));
    121     EXPECT_TRUE(err.has_error());
    122   }
    123 
    124   // Mark used.
    125   {
    126     Scope new_scope(setup.settings());
    127 
    128     Err err;
    129     Scope::MergeOptions options;
    130     options.mark_used = true;
    131     EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
    132         &new_scope, options, &assignment, "error", &err));
    133     EXPECT_FALSE(err.has_error());
    134     EXPECT_TRUE(new_scope.CheckForUnusedVars(&err));
    135     EXPECT_FALSE(err.has_error());
    136   }
    137 }
    138 
    139 TEST(Scope, MakeClosure) {
    140   // Create 3 nested scopes [const root from setup] <- nested1 <- nested2.
    141   TestWithScope setup;
    142 
    143   // Make a pretend parse node with proper tracking that we can blame for the
    144   // given value.
    145   InputFile input_file(SourceFile("//foo"));
    146   Token assignment_token(Location(&input_file, 1, 1), Token::STRING,
    147       "\"hello\"");
    148   LiteralNode assignment;
    149   assignment.set_value(assignment_token);
    150   setup.scope()->SetValue("on_root", Value(&assignment, "on_root"),
    151                            &assignment);
    152 
    153   // Root scope should be const from the nested caller's perspective.
    154   Scope nested1(static_cast<const Scope*>(setup.scope()));
    155   nested1.SetValue("on_one", Value(&assignment, "on_one"), &assignment);
    156 
    157   Scope nested2(&nested1);
    158   nested2.SetValue("on_one", Value(&assignment, "on_two"), &assignment);
    159   nested2.SetValue("on_two", Value(&assignment, "on_two2"), &assignment);
    160 
    161   // Making a closure from the root scope.
    162   scoped_ptr<Scope> result = setup.scope()->MakeClosure();
    163   EXPECT_FALSE(result->containing());  // Should have no containing scope.
    164   EXPECT_TRUE(result->GetValue("on_root"));  // Value should be copied.
    165 
    166   // Making a closure from the second nested scope.
    167   result = nested2.MakeClosure();
    168   EXPECT_EQ(setup.scope(),
    169             result->containing());  // Containing scope should be the root.
    170   EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_root", "on_root"));
    171   EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_one", "on_two"));
    172   EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_two", "on_two2"));
    173 }
    174 
    175 TEST(Scope, GetMutableValue) {
    176   TestWithScope setup;
    177 
    178   // Make a pretend parse node with proper tracking that we can blame for the
    179   // given value.
    180   InputFile input_file(SourceFile("//foo"));
    181   Token assignment_token(Location(&input_file, 1, 1), Token::STRING,
    182       "\"hello\"");
    183   LiteralNode assignment;
    184   assignment.set_value(assignment_token);
    185 
    186   const char kOnConst[] = "on_const";
    187   const char kOnMutable1[] = "on_mutable1";
    188   const char kOnMutable2[] = "on_mutable2";
    189 
    190   Value value(&assignment, "hello");
    191 
    192   // Create a root scope with one value.
    193   Scope root_scope(setup.settings());
    194   root_scope.SetValue(kOnConst, value, &assignment);
    195 
    196   // Create a first nested scope with a different value.
    197   const Scope* const_root_scope = &root_scope;
    198   Scope mutable_scope1(const_root_scope);
    199   mutable_scope1.SetValue(kOnMutable1, value, &assignment);
    200 
    201   // Create a second nested scope with a different value.
    202   Scope mutable_scope2(&mutable_scope1);
    203   mutable_scope2.SetValue(kOnMutable2, value, &assignment);
    204 
    205   // Check getting root scope values.
    206   EXPECT_TRUE(mutable_scope2.GetValue(kOnConst, true));
    207   EXPECT_FALSE(mutable_scope2.GetMutableValue(kOnConst, true));
    208 
    209   // Test reading a value from scope 1.
    210   Value* mutable1_result = mutable_scope2.GetMutableValue(kOnMutable1, false);
    211   ASSERT_TRUE(mutable1_result);
    212   EXPECT_TRUE(*mutable1_result == value);
    213 
    214   // Make sure CheckForUnusedVars works on scope1 (we didn't mark the value as
    215   // used in the previous step).
    216   Err err;
    217   EXPECT_FALSE(mutable_scope1.CheckForUnusedVars(&err));
    218   mutable1_result = mutable_scope2.GetMutableValue(kOnMutable1, true);
    219   EXPECT_TRUE(mutable1_result);
    220   err = Err();
    221   EXPECT_TRUE(mutable_scope1.CheckForUnusedVars(&err));
    222 
    223   // Test reading a value from scope 2.
    224   Value* mutable2_result = mutable_scope2.GetMutableValue(kOnMutable2, true);
    225   ASSERT_TRUE(mutable2_result);
    226   EXPECT_TRUE(*mutable2_result == value);
    227 }
    228 
    229 TEST(Scope, RemovePrivateIdentifiers) {
    230   TestWithScope setup;
    231   setup.scope()->SetValue("a", Value(NULL, true), NULL);
    232   setup.scope()->SetValue("_b", Value(NULL, true), NULL);
    233 
    234   setup.scope()->RemovePrivateIdentifiers();
    235   EXPECT_TRUE(setup.scope()->GetValue("a"));
    236   EXPECT_FALSE(setup.scope()->GetValue("_b"));
    237 }
    238