def test_handles_empty_generators(self): def function_calling_empty_generator(): def generator(x): if False: yield 'something' [x for x in generator(123)] execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(function_calling_empty_generator, execution) assert_function_with_single_generator_object("generator", {'x': 123}, [], execution)
def test_handles_generator_objects_that_werent_destroyed(self): def function(): def generator(): yield 1 g = generator() g.next() globals()['__generator_yielding_one'] = g execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(function, execution) assert_function_with_single_generator_object("generator", {}, [1], execution)
def inspect_returning_callables_and_execution(fun, ignored_functions=None): project = ProjectMock(ignored_functions or []) execution = Execution(project=project) try: inspect_code_in_context(fun, execution) # Don't allow any POEs exceptions to propagate to the testing code. # Catch both string and normal exceptions. except: print "Caught exception inside point of entry:", last_exception_as_string() print last_traceback() return project.get_callables(), execution
def inspect_returning_callables_and_execution(fun, ignored_functions=None): project = ProjectMock(ignored_functions or []) execution = Execution(project=project) try: inspect_code_in_context(fun, execution) # Don't allow any POEs exceptions to propagate to the testing code. # Catch both string and normal exceptions. except: print("Caught exception inside point of entry:", last_exception_as_string()) print(last_traceback()) return project.get_callables(), execution
def test_handles_single_yielded_value(self): def yields_one(): def generator(): yield 1 g = generator() g.next() execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(yields_one, execution) generator = execution.project.find_object(Function, "generator") gobject = assert_one_element_and_return(generator.calls) assert_generator_object({}, [1], gobject)
def test_handles_generator_objects_that_yield_none_and_dont_get_destroyed(self): if hasattr(generator_has_ended, 'unreliable'): raise SkipTest def function(): def generator(): yield None g = generator() g.next() globals()['__generator_yielding_none'] = g execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(function, execution) assert_function_with_single_generator_object("generator", {}, [None], execution)
def test_handles_yielded_values(self): def function_calling_generator(): def generator(x): yield x yield x + 1 yield x * 2 yield x ** 3 [x for x in generator(2)] execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(function_calling_generator, execution) generator = execution.project.find_object(Function, "generator") gobject = assert_one_element_and_return(generator.calls) assert_generator_object({'x': 2}, [2, 3, 4, 8], gobject)
def test_handles_yielded_nones(self): if hasattr(generator_has_ended, 'unreliable'): raise SkipTest def yields_none(): def generator(): yield None g = generator() g.next() execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(yields_none, execution) generator = execution.project.find_object(Function, "generator") gobject = assert_one_element_and_return(generator.calls) assert_generator_object({}, [None], gobject)
def test_handles_generators_called_not_from_top_level(self): def function_calling_function_that_uses_generator(): def generator(x): yield x yield x + 1 yield x * 2 yield x ** 3 def function(y): return [x for x in generator(y)] function(2) execution = TestingProject()\ .with_all_catch_module()\ .with_object(Function("generator", is_generator=True))\ .with_object(Function("function"))\ .make_new_execution() inspect_code_in_context(function_calling_function_that_uses_generator, execution) assert_function_with_single_generator_object("generator", {'x': 2}, [2, 3, 4, 8], execution)
def test_handles_generator_methods(self): def function_calling_generator_method(): class GenClass(object): def genmeth(self): yield 0 yield 1 yield 0 [x for x in GenClass().genmeth()] execution = TestingProject()\ .with_all_catch_module()\ .with_object(Class("GenClass", methods=[Method("genmeth", is_generator=True)]))\ .make_new_execution() inspect_code_in_context(function_calling_generator_method, execution) klass = execution.project.find_object(Class, "GenClass") user_object = assert_one_element_and_return(klass.user_objects) assert_instance(user_object, UserObject) gobject = assert_one_element_and_return(user_object.calls) assert_generator_object({}, [0, 1, 0], gobject)
def test_generator_can_be_invoked_in_multiple_places(self): def function(): def generator(): i = 1 while True: yield i i += 1 def first(g): return g.next() def second(g): return g.next() + g.next() g = generator() g.next() first(g) second(g) execution = TestingProject()\ .with_all_catch_module()\ .with_object(Function("generator", is_generator=True))\ .with_object(Function("first"))\ .with_object(Function("second"))\ .make_new_execution() inspect_code_in_context(function, execution) expected_call_graph = noindent(""" generator() first() next() generator() second() next() generator() next() generator() """) assert_equal_strings(expected_call_graph, call_graph_as_string(execution.call_graph))
def test_generator_can_be_invoked_multiple_times_at_the_same_place(self): def function(): def sth_else(): return False def generator(): yield 1 yield 2 g = generator() g.next() sth_else() g.next() execution = TestingProject()\ .with_all_catch_module()\ .with_object(Function("generator", is_generator=True))\ .with_object(Function("sth_else"))\ .make_new_execution() inspect_code_in_context(function, execution) assert_instance(execution.call_graph[0], GeneratorObjectInvocation) assert_instance(execution.call_graph[1], FunctionCall) assert_instance(execution.call_graph[2], GeneratorObjectInvocation)
def test_distinguishes_between_generator_objects_spawned_with_the_same_generator(self): def function(): def generator(): yield 1 yield 2 [x for x in generator()] [x for x in generator()] execution = make_execution_with_single_generator_function("generator") inspect_code_in_context(function, execution) generator = execution.project.find_object(Function, "generator") assert_length(generator.calls, 2) assert_length(execution.call_graph, 4) gcall1 = generator.calls[0] assert gcall1.calls[0] is execution.call_graph[0] assert gcall1.calls[1] is execution.call_graph[1] gcall2 = generator.calls[1] assert gcall2.calls[0] is execution.call_graph[2] assert gcall2.calls[1] is execution.call_graph[3]
def test_serializes_generator_objects_passed_as_values(self): def function(): def invoke(g): return [x for x in g] def generator(): yield 1 yield 2 invoke(generator()) execution = TestingProject()\ .with_all_catch_module()\ .with_object(Function("invoke"))\ .with_object(Function("generator", is_generator=True))\ .make_new_execution() inspect_code_in_context(function, execution) function = execution.project.find_object(Function, "invoke") fcall = assert_one_element_and_return(function.calls) gobject = fcall.input['g'] assert_instance(gobject, GeneratorObject) assert_generator_object({}, [1, 2], gobject)