this repo has no description
at trunk 413 lines 15 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "module-builtins.h" 3 4#include "gtest/gtest.h" 5 6#include "attributedict.h" 7#include "builtins.h" 8#include "dict-builtins.h" 9#include "ic.h" 10#include "object-builtins.h" 11#include "objects.h" 12#include "runtime.h" 13#include "str-builtins.h" 14#include "test-utils.h" 15 16namespace py { 17namespace testing { 18 19using ModuleBuiltinsDeathTest = RuntimeFixture; 20using ModuleBuiltinsTest = RuntimeFixture; 21 22TEST_F(ModuleBuiltinsTest, DunderName) { 23 ASSERT_FALSE(runFromCStr(runtime_, R"( 24import sys 25a = sys.__name__ 26)") 27 .isError()); 28 HandleScope scope(thread_); 29 Str a(&scope, mainModuleAt(runtime_, "a")); 30 EXPECT_TRUE(a.equalsCStr("sys")); 31} 32 33TEST_F(ModuleBuiltinsTest, DunderNameOverwritesDoesNotAffectModuleNameField) { 34 ASSERT_FALSE(runFromCStr(runtime_, R"( 35import sys 36sys.__name__ = "ysy" 37)") 38 .isError()); 39 HandleScope scope(thread_); 40 Module sys_module(&scope, mainModuleAt(runtime_, "sys")); 41 EXPECT_TRUE(isStrEqualsCStr(sys_module.name(), "sys")); 42} 43 44// TODO(T39575976): Add tests verifying internal names's hiding. 45TEST_F(ModuleBuiltinsTest, DunderGetattributeReturnsAttribute) { 46 HandleScope scope(thread_); 47 ASSERT_FALSE(runFromCStr(runtime_, "foo = -6").isError()); 48 Module module(&scope, runtime_->findModuleById(ID(__main__))); 49 Object name(&scope, runtime_->newStrFromCStr("foo")); 50 EXPECT_TRUE(isIntEqualsWord( 51 runBuiltin(METH(module, __getattribute__), module, name), -6)); 52} 53 54TEST_F(ModuleBuiltinsTest, DunderGetattributeWithNonStringNameRaisesTypeError) { 55 HandleScope scope(thread_); 56 ASSERT_FALSE(runFromCStr(runtime_, "").isError()); 57 Module module(&scope, runtime_->findModuleById(ID(__main__))); 58 Object name(&scope, runtime_->newInt(0)); 59 EXPECT_TRUE(raisedWithStr( 60 runBuiltin(METH(module, __getattribute__), module, name), 61 LayoutId::kTypeError, "attribute name must be string, not 'int'")); 62} 63 64TEST_F(ModuleBuiltinsTest, 65 DunderGetattributeWithMissingAttributeRaisesAttributeError) { 66 HandleScope scope(thread_); 67 ASSERT_FALSE(runFromCStr(runtime_, "").isError()); 68 Module module(&scope, runtime_->findModuleById(ID(__main__))); 69 Object name(&scope, runtime_->newStrFromCStr("xxx")); 70 EXPECT_TRUE(raisedWithStr( 71 runBuiltin(METH(module, __getattribute__), module, name), 72 LayoutId::kAttributeError, "module '__main__' has no attribute 'xxx'")); 73} 74 75TEST_F(ModuleBuiltinsTest, DunderSetattrSetsAttribute) { 76 HandleScope scope(thread_); 77 Object module_name(&scope, runtime_->newStrFromCStr("foo")); 78 Module module(&scope, runtime_->newModule(module_name)); 79 Object name(&scope, Runtime::internStrFromCStr(thread_, "foobarbaz")); 80 Object value(&scope, runtime_->newInt(0xf00d)); 81 EXPECT_TRUE( 82 runBuiltin(METH(module, __setattr__), module, name, value).isNoneType()); 83 EXPECT_TRUE(isIntEqualsWord(moduleAt(module, name), 0xf00d)); 84} 85 86TEST_F(ModuleBuiltinsTest, DunderSetattrWithNonStrNameRaisesTypeError) { 87 HandleScope scope(thread_); 88 Object module_name(&scope, runtime_->newStrFromCStr("foo")); 89 Object module(&scope, runtime_->newModule(module_name)); 90 Object name(&scope, runtime_->newFloat(4.4)); 91 Object value(&scope, runtime_->newInt(0)); 92 EXPECT_TRUE(raisedWithStr( 93 runBuiltin(METH(module, __setattr__), module, name, value), 94 LayoutId::kTypeError, "attribute name must be string, not 'float'")); 95} 96 97TEST_F(ModuleBuiltinsTest, DunderDict) { 98 ASSERT_FALSE(runFromCStr(runtime_, R"( 99import sys 100result = sys.__dict__ 101)") 102 .isError()); 103 HandleScope scope(thread_); 104 Object result(&scope, mainModuleAt(runtime_, "result")); 105 EXPECT_TRUE(result.isModuleProxy()); 106} 107 108static RawModule createTestingModule(Thread* thread) { 109 HandleScope scope(thread); 110 Runtime* runtime = thread->runtime(); 111 112 // Create a builtins module. 113 Object builtins_name(&scope, runtime->symbols()->at(ID(builtins))); 114 Module builtins_module(&scope, runtime->newModule(builtins_name)); 115 116 // Create a module dict with builtins in it. 117 Object name(&scope, Runtime::internStrFromCStr(thread, "<test module>")); 118 Module module(&scope, runtime->newModule(name)); 119 moduleAtPutById(thread, module, ID(__builtins__), builtins_module); 120 return *module; 121} 122 123TEST_F(ModuleBuiltinsTest, ModuleAtIgnoresBuiltinsEntry) { 124 HandleScope scope(thread_); 125 Module module(&scope, createTestingModule(thread_)); 126 Module builtins(&scope, moduleAtById(thread_, module, ID(__builtins__))); 127 128 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 129 Str foo_in_builtins(&scope, runtime_->newStrFromCStr("foo_in_builtins")); 130 moduleAtPut(thread_, builtins, foo, foo_in_builtins); 131 EXPECT_TRUE(moduleAt(module, foo).isErrorNotFound()); 132} 133 134TEST_F(ModuleBuiltinsTest, ModuleAtReturnsValuePutByModuleAtPut) { 135 HandleScope scope(thread_); 136 Module module(&scope, createTestingModule(thread_)); 137 Object name(&scope, Runtime::internStrFromCStr(thread_, "a")); 138 Object value(&scope, runtime_->newStrFromCStr("a's value")); 139 moduleAtPut(thread_, module, name, value); 140 EXPECT_EQ(moduleAt(module, name), *value); 141} 142 143TEST_F(ModuleBuiltinsTest, ModuleAtReturnsErrorNotFoundForPlaceholder) { 144 HandleScope scope(thread_); 145 Module module(&scope, createTestingModule(thread_)); 146 Object name(&scope, Runtime::internStrFromCStr(thread_, "a")); 147 Object value(&scope, runtime_->newStrFromCStr("a's value")); 148 moduleAtPut(thread_, module, name, value); 149 150 RawObject value_cell = NoneType::object(); 151 EXPECT_TRUE(attributeValueCellAt(*module, *name, &value_cell)); 152 ValueCell::cast(value_cell).makePlaceholder(); 153 EXPECT_TRUE(moduleAt(module, name).isErrorNotFound()); 154} 155 156TEST_F(ModuleBuiltinsTest, ModuleAtByIdReturnsValuePutByModuleAtPutById) { 157 HandleScope scope(thread_); 158 Module module(&scope, createTestingModule(thread_)); 159 Object value(&scope, runtime_->newStrFromCStr("a's value")); 160 moduleAtPutById(thread_, module, ID(NotImplemented), value); 161 EXPECT_EQ(moduleAtById(thread_, module, ID(NotImplemented)), *value); 162} 163 164TEST_F(ModuleBuiltinsTest, ModuleAtReturnsValuePutByModuleAtPutByCStr) { 165 HandleScope scope(thread_); 166 Module module(&scope, createTestingModule(thread_)); 167 Object value(&scope, runtime_->newStrFromCStr("a's value")); 168 const char* name_cstr = "a"; 169 moduleAtPutByCStr(thread_, module, name_cstr, value); 170 Object name(&scope, Runtime::internStrFromCStr(thread_, name_cstr)); 171 EXPECT_EQ(moduleAt(module, name), *value); 172} 173 174TEST_F(ModuleBuiltinsTest, 175 ModuleAtPutDoesNotInvalidateCachedModuleDictValueCell) { 176 HandleScope scope(thread_); 177 EXPECT_FALSE(runFromCStr(runtime_, R"( 178a = 4 179 180def foo(): 181 return a 182 183foo() 184)") 185 .isError()); 186 Module module(&scope, findMainModule(runtime_)); 187 Object a(&scope, Runtime::internStrFromCStr(thread_, "a")); 188 ValueCell value_cell_a(&scope, moduleValueCellAt(thread_, module, a)); 189 190 // The looked up module entry got cached in function foo(). 191 Function function_foo(&scope, mainModuleAt(runtime_, "foo")); 192 MutableTuple caches(&scope, function_foo.caches()); 193 ASSERT_EQ(icLookupGlobalVar(*caches, 0), *value_cell_a); 194 195 // Updating global variable a does not invalidate the cache. 196 Str new_value(&scope, runtime_->newStrFromCStr("value")); 197 moduleAtPut(thread_, module, a, new_value); 198 EXPECT_EQ(icLookupGlobalVar(*caches, 0), *value_cell_a); 199 EXPECT_EQ(value_cell_a.value(), *new_value); 200} 201 202TEST_F(ModuleBuiltinsTest, ModuleAtPutInvalidatesCachedBuiltinsValueCell) { 203 HandleScope scope(thread_); 204 EXPECT_FALSE(runFromCStr(runtime_, R"( 205__builtins__.a = 4 206 207def foo(): 208 return a 209 210foo() 211)") 212 .isError()); 213 Module module(&scope, findMainModule(runtime_)); 214 Module builtins(&scope, runtime_->findModuleById(ID(builtins))); 215 Object a(&scope, Runtime::internStrFromCStr(thread_, "a")); 216 Str new_value(&scope, runtime_->newStrFromCStr("value")); 217 ValueCell value_cell_a(&scope, moduleValueCellAt(thread_, builtins, a)); 218 219 // The looked up module entry got cached in function foo(). 220 Function function_foo(&scope, mainModuleAt(runtime_, "foo")); 221 MutableTuple caches(&scope, function_foo.caches()); 222 ASSERT_EQ(icLookupGlobalVar(*caches, 0), *value_cell_a); 223 224 ASSERT_FALSE(mainModuleAt(runtime_, "__builtins__").isErrorNotFound()); 225 226 // Updating global variable a does invalidate the cache since it shadows 227 // __builtins__.a. 228 moduleAtPut(thread_, module, a, new_value); 229 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType()); 230} 231 232TEST_F(ModuleBuiltinsTest, ModuleKeysFiltersOutPlaceholders) { 233 HandleScope scope(thread_); 234 Str name(&scope, Str::empty()); 235 Module module(&scope, runtime_->newModule(name)); 236 attributeDictInit(thread_, module); 237 238 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 239 Object bar(&scope, Runtime::internStrFromCStr(thread_, "bar")); 240 Object baz(&scope, Runtime::internStrFromCStr(thread_, "baz")); 241 Str value(&scope, runtime_->newStrFromCStr("value")); 242 243 moduleAtPut(thread_, module, foo, value); 244 moduleAtPut(thread_, module, bar, value); 245 moduleAtPut(thread_, module, baz, value); 246 247 ValueCell::cast(moduleValueCellAt(thread_, module, bar)).makePlaceholder(); 248 249 List keys(&scope, moduleKeys(thread_, module)); 250 EXPECT_EQ(keys.numItems(), 2); 251 EXPECT_EQ(keys.at(0), *foo); 252 EXPECT_EQ(keys.at(1), *baz); 253} 254 255TEST_F(ModuleBuiltinsTest, ModuleLenReturnsItemCountExcludingPlaceholders) { 256 HandleScope scope(thread_); 257 Object module_name(&scope, Runtime::internStrFromCStr(thread_, "mymodule")); 258 Module module(&scope, runtime_->newModule(module_name)); 259 260 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 261 Object bar(&scope, Runtime::internStrFromCStr(thread_, "bar")); 262 Object baz(&scope, Runtime::internStrFromCStr(thread_, "baz")); 263 Str value(&scope, runtime_->newStrFromCStr("value")); 264 265 moduleAtPut(thread_, module, foo, value); 266 moduleAtPut(thread_, module, bar, value); 267 moduleAtPut(thread_, module, baz, value); 268 269 word previous_len = moduleLen(thread_, module); 270 271 RawObject value_cell = NoneType::object(); 272 EXPECT_TRUE(attributeValueCellAt(*module, *bar, &value_cell)); 273 ValueCell::cast(value_cell).makePlaceholder(); 274 275 word after_len = moduleLen(thread_, module); 276 EXPECT_EQ(previous_len, after_len + 1); 277} 278 279TEST_F(ModuleBuiltinsTest, ModuleRemoveInvalidatesCachedModuleDictValueCell) { 280 HandleScope scope(thread_); 281 EXPECT_FALSE(runFromCStr(runtime_, R"( 282a = 4 283 284def foo(): 285 return a 286 287foo() 288)") 289 .isError()); 290 291 // The looked up module entry got cached in function foo(). 292 Function function_foo(&scope, mainModuleAt(runtime_, "foo")); 293 MutableTuple caches(&scope, function_foo.caches()); 294 295 Module module(&scope, findMainModule(runtime_)); 296 Str a(&scope, runtime_->newStrFromCStr("a")); 297 ASSERT_EQ(icLookupGlobalVar(*caches, 0), 298 moduleValueCellAt(thread_, module, a)); 299 300 EXPECT_FALSE(moduleRemove(thread_, module, a).isError()); 301 EXPECT_TRUE(icLookupGlobalVar(*caches, 0).isNoneType()); 302} 303 304TEST_F(ModuleBuiltinsTest, ModuleValuesFiltersOutPlaceholders) { 305 HandleScope scope(thread_); 306 Str module_name(&scope, runtime_->newStrFromCStr("mymodule")); 307 Module module(&scope, runtime_->newModule(module_name)); 308 309 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 310 Str foo_value(&scope, runtime_->newStrFromCStr("foo_value")); 311 Object bar(&scope, Runtime::internStrFromCStr(thread_, "bar")); 312 Str bar_value(&scope, runtime_->newStrFromCStr("bar_value")); 313 Object baz(&scope, Runtime::internStrFromCStr(thread_, "baz")); 314 Str baz_value(&scope, runtime_->newStrFromCStr("baz_value")); 315 316 moduleAtPut(thread_, module, foo, foo_value); 317 moduleAtPut(thread_, module, bar, bar_value); 318 moduleAtPut(thread_, module, baz, baz_value); 319 320 RawObject value_cell = NoneType::object(); 321 EXPECT_TRUE(attributeValueCellAt(*module, *bar, &value_cell)); 322 ValueCell::cast(value_cell).makePlaceholder(); 323 324 List values(&scope, moduleValues(thread_, module)); 325 EXPECT_TRUE(listContains(values, foo_value)); 326 EXPECT_FALSE(listContains(values, bar_value)); 327 EXPECT_TRUE(listContains(values, baz_value)); 328} 329 330TEST_F(ModuleBuiltinsTest, ModuleDelAttrEmptiesValueCell) { 331 HandleScope scope(thread_); 332 Str module_name(&scope, runtime_->newStrFromCStr("mymodule")); 333 Module module(&scope, runtime_->newModule(module_name)); 334 335 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 336 Str foo_value(&scope, runtime_->newStrFromCStr("foo_value")); 337 338 moduleAtPut(thread_, module, foo, foo_value); 339 340 Object value_cell(&scope, NoneType::object()); 341 EXPECT_TRUE(attributeValueCellAt(*module, *foo, &value_cell)); 342 EXPECT_EQ(ValueCell::cast(*value_cell).value(), *foo_value); 343 moduleDeleteAttribute(thread_, module, foo); 344 EXPECT_NE(ValueCell::cast(*value_cell).value(), *foo_value); 345 EXPECT_TRUE(ValueCell::cast(*value_cell).isPlaceholder()); 346} 347 348TEST_F(ModuleBuiltinsTest, ModuleGetAttributeReturnsInstanceValue) { 349 HandleScope scope(thread_); 350 ASSERT_FALSE(runFromCStr(runtime_, "x = 42").isError()); 351 Module module(&scope, runtime_->findModuleById(ID(__main__))); 352 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 353 EXPECT_TRUE(isIntEqualsWord(moduleGetAttribute(thread_, module, name), 42)); 354} 355 356TEST_F(ModuleBuiltinsTest, ModuleGetAttributeWithNonExistentNameReturnsError) { 357 HandleScope scope(thread_); 358 Object module_name(&scope, runtime_->newStrFromCStr("")); 359 Module module(&scope, runtime_->newModule(module_name)); 360 Object name(&scope, Runtime::internStrFromCStr(thread_, "xxx")); 361 EXPECT_TRUE(moduleGetAttribute(thread_, module, name).isError()); 362 EXPECT_FALSE(thread_->hasPendingException()); 363} 364 365TEST_F(ModuleBuiltinsTest, ModuleSetAttrSetsAttribute) { 366 HandleScope scope(thread_); 367 Object module_name(&scope, runtime_->newStrFromCStr("foo")); 368 Module module(&scope, runtime_->newModule(module_name)); 369 Object name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 370 Object value(&scope, runtime_->newInt(-543)); 371 EXPECT_TRUE(moduleSetAttr(thread_, module, name, value).isNoneType()); 372 EXPECT_TRUE(isIntEqualsWord(moduleAt(module, name), -543)); 373} 374 375TEST_F(ModuleBuiltinsTest, NewModuleDunderReprReturnsString) { 376 HandleScope scope(thread_); 377 Object name(&scope, runtime_->newStrFromCStr("hello")); 378 Object module(&scope, runtime_->newModule(name)); 379 Object result(&scope, Thread::current()->invokeMethod1(module, ID(__repr__))); 380 EXPECT_TRUE(isStrEqualsCStr(*result, "<module 'hello'>")); 381} 382 383TEST_F(ModuleBuiltinsTest, BuiltinModuleDunderReprReturnsString) { 384 ASSERT_FALSE(runFromCStr(runtime_, R"( 385import sys 386result = sys.__repr__() 387)") 388 .isError()); 389 HandleScope scope(thread_); 390 Object result(&scope, mainModuleAt(runtime_, "result")); 391 EXPECT_TRUE(isStrEqualsCStr(*result, "<module 'sys' (built-in)>")); 392} 393 394TEST_F(ModuleBuiltinsTest, ModuleIsMarkedAsCustomDict) { 395 HandleScope scope(thread_); 396 Type type(&scope, runtime_->typeAt(LayoutId::kModule)); 397 EXPECT_TRUE(type.hasFlag(Type::Flag::kHasCustomDict)); 398 EXPECT_TRUE(Layout::cast(type.instanceLayout()).isSealed()); 399} 400 401TEST_F(ModuleBuiltinsTest, ModuleSubclassLayoutIsSealed) { 402 HandleScope scope(thread_); 403 EXPECT_FALSE(runFromCStr(runtime_, R"( 404class C(module): pass 405)") 406 .isError()); 407 Type type(&scope, mainModuleAt(runtime_, "C")); 408 EXPECT_TRUE(type.hasFlag(Type::Flag::kHasCustomDict)); 409 EXPECT_TRUE(Layout::cast(type.instanceLayout()).isSealed()); 410} 411 412} // namespace testing 413} // namespace py