this repo has no description
at trunk 232 lines 5.3 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "gtest/gtest.h" 3 4#include "objects.h" 5#include "runtime.h" 6#include "test-utils.h" 7 8namespace py { 9namespace testing { 10 11using CoroutineTest = RuntimeFixture; 12using GeneratorTest = RuntimeFixture; 13using AsyncGeneratorTest = RuntimeFixture; 14 15TEST_F(GeneratorTest, Basic) { 16 const char* src = R"( 17def fib(n): 18 a = 0 19 b = 1 20 for i in range(n): 21 yield a 22 a, b = a + b, a 23 24result = [i for i in fib(7)] 25)"; 26 27 HandleScope scope(thread_); 28 ASSERT_FALSE(runFromCStr(runtime_, src).isError()); 29 Object result(&scope, mainModuleAt(runtime_, "result")); 30 EXPECT_PYLIST_EQ(result, {0, 1, 1, 2, 3, 5, 8}); 31} 32 33TEST_F(GeneratorTest, InitialSend) { 34 HandleScope scope(thread_); 35 ASSERT_FALSE(runFromCStr(runtime_, R"( 36def gen(): 37 global value 38 value = 3 39 value += yield 0 40 yield 'dummy' 41 42g = gen() 43g.send(None) 44g.send(7) 45)") 46 .isError()); 47 Object result(&scope, mainModuleAt(runtime_, "value")); 48 EXPECT_TRUE(isIntEqualsWord(*result, 10)); 49} 50 51TEST_F(GeneratorTest, BadInitialSend) { 52 const char* src = R"( 53def gen(): 54 yield 0 55gen().send(1) 56)"; 57 EXPECT_TRUE( 58 raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError, 59 "can't send non-None value to a just-started generator")); 60} 61 62TEST_F(GeneratorTest, YieldFrom) { 63 HandleScope scope(thread_); 64 ASSERT_FALSE(runFromCStr(runtime_, R"( 65result = [] 66def log(obj): 67 global result 68 result.append(obj) 69 70def str_maker(l): 71 while True: 72 val = yield l 73 if val is None: 74 break 75 l += ' ' + val 76 yield from range(5) 77 return 'finished!' 78 79def g1(): 80 start = yield 'ready' 81 x = yield from str_maker(start) 82 log(x) 83 84g = g1() 85log('priming') 86log(g.__next__()) 87log('sending') 88initial_str = 'initial string' 89log(g.send(initial_str)) 90log(g.send('first')) 91log(g.send('second')) 92log(g.send(None)) 93for i in g: 94 log(i) 95)") 96 .isError()); 97 Object result(&scope, mainModuleAt(runtime_, "result")); 98 EXPECT_PYLIST_EQ( 99 result, 100 {"priming", "ready", "sending", "initial string", "initial string first", 101 "initial string first second", 0, 1, 2, 3, 4, "finished!"}); 102 103 // Manually check element 3 for object identity 104 ASSERT_TRUE(result.isList()); 105 List list(&scope, *result); 106 Object initial(&scope, mainModuleAt(runtime_, "initial_str")); 107 EXPECT_GE(list.numItems(), 3); 108 EXPECT_EQ(list.at(3), *initial); 109} 110 111TEST_F(GeneratorTest, ReraiseAfterYield) { 112 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 113def gen(): 114 try: 115 raise RuntimeError("inside generator") 116 except: 117 yield 118 raise 119 120g = gen() 121g.__next__() 122try: 123 raise RuntimeError("outside generator") 124except: 125 g.__next__() 126)"), 127 LayoutId::kRuntimeError, "inside generator")); 128} 129 130TEST_F(GeneratorTest, ReturnFromTrySkipsExcept) { 131 HandleScope scope(thread_); 132 ASSERT_FALSE(runFromCStr(runtime_, R"( 133result = 0 134 135def gen(): 136 global result 137 yield 0 138 try: 139 return 123 140 except: 141 result = -1 142 yield 1 143 144g = gen() 145g.__next__() 146try: 147 g.__next__() 148except StopIteration: 149 result = 1 150)") 151 .isError()); 152 153 Object result(&scope, mainModuleAt(runtime_, "result")); 154 ASSERT_TRUE(result.isSmallInt()); 155 EXPECT_EQ(SmallInt::cast(*result).value(), 1); 156} 157 158TEST_F(GeneratorTest, NextAfterReturnRaisesStopIteration) { 159 EXPECT_EQ(runFromCStr(runtime_, R"( 160def gen(): 161 yield 0 162 return "hello there" 163 164g = gen() 165g.__next__() 166)"), 167 NoneType::object()); 168 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "g.__next__()"), 169 LayoutId::kStopIteration, "hello there")); 170 thread_->clearPendingException(); 171 EXPECT_TRUE( 172 raised(runFromCStr(runtime_, "g.__next__()"), LayoutId::kStopIteration)); 173 thread_->clearPendingException(); 174 EXPECT_TRUE( 175 raised(runFromCStr(runtime_, "g.__next__()"), LayoutId::kStopIteration)); 176} 177 178TEST_F(GeneratorTest, NextAfterRaiseRaisesStopIteration) { 179 EXPECT_FALSE(runFromCStr(runtime_, R"( 180def gen(): 181 yield 0 182 raise RuntimeError("kaboom") 183 yield 1 184 185g = gen() 186g.__next__() 187)") 188 .isError()); 189 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, "g.__next__()"), 190 LayoutId::kRuntimeError, "kaboom")); 191 thread_->clearPendingException(); 192 EXPECT_TRUE( 193 raised(runFromCStr(runtime_, "g.__next__()"), LayoutId::kStopIteration)); 194} 195 196TEST_F(CoroutineTest, Basic) { 197 HandleScope scope(thread_); 198 ASSERT_FALSE(runFromCStr(runtime_, R"( 199async def coro(): 200 return 24 201c = coro() 202)") 203 .isError()); 204 Object result(&scope, mainModuleAt(runtime_, "c")); 205 EXPECT_TRUE(result.isCoroutine()); 206} 207 208TEST_F(CoroutineTest, BadInitialSend) { 209 const char* src = R"( 210async def coro(): 211 return 0 212coro().send(1) 213)"; 214 EXPECT_TRUE( 215 raisedWithStr(runFromCStr(runtime_, src), LayoutId::kTypeError, 216 "can't send non-None value to a just-started coroutine")); 217} 218 219TEST_F(AsyncGeneratorTest, Create) { 220 HandleScope scope(thread_); 221 ASSERT_FALSE(runFromCStr(runtime_, R"( 222async def async_gen(): 223 yield 1234 224ag = async_gen() 225)") 226 .isError()); 227 Object result(&scope, mainModuleAt(runtime_, "ag")); 228 EXPECT_TRUE(result.isAsyncGenerator()); 229} 230 231} // namespace testing 232} // namespace py