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