def type_as_string(obj): """Return a most common representation of the wrapped object type. >>> type_as_string([SequenceObject((), None), MapObject({}, None)]) '[tuple, dict]' >>> cs = type_as_string(UnknownObject(lambda: None)) >>> cs 'types.FunctionType' >>> cs.imports set(['types']) """ if isinstance(obj, list): return list_of( map(type_as_string, obj)) # TODO join preserving code strings attributes type2import = { 'time': ('datetime', 'time'), 'datetime': ('datetime', 'datetime'), 'date': ('datetime', 'date') } cs = CodeString(obj.type_name) if cs.startswith('types.'): return addimport(cs, 'types') elif str(cs) in type2import.keys(): # TODO it should be done in the serializer return addimport(cs, type2import[str(cs)]) return cs
def call_in_test(call, already_assigned_names): if isinstance(call, GeneratorObject) or (isinstance(call, MethodCallContext) and isinstance(call.call, GeneratorObject)): callstring = call_as_string_for(call_name(call, already_assigned_names), call.args, call.definition, already_assigned_names) callstring = combine(callstring, str(len(call.calls)), template="list(islice(%s, %s))") callstring = addimport(callstring, ("itertools", "islice")) else: callstring = call_as_string_for(call_name(call, already_assigned_names), call.input, call.definition, already_assigned_names) callstring = addimport(callstring, import_for(call.definition)) return callstring
def type_as_string(obj): """Return a most common representation of the wrapped object type. >>> type_as_string([SequenceObject((), None), MapObject({}, None)]) '[tuple, dict]' >>> cs = type_as_string(UnknownObject(lambda: None)) >>> cs 'types.FunctionType' >>> cs.imports set(['types']) """ if isinstance(obj, list): return list_of(map(type_as_string, obj)) # TODO join preserving code strings attributes type2import = {'time': ('datetime', 'time'), 'datetime': ('datetime', 'datetime'), 'date': ('datetime', 'date')} cs = CodeString(obj.type_name) if cs.startswith('types.'): return addimport(cs, 'types') elif str(cs) in type2import.keys(): # TODO it should be done in the serializer return addimport(cs, type2import[str(cs)]) return cs
def skip_test(self): return addimport( CodeString("raise SkipTest # TODO: implement your test here"), ('nose', 'SkipTest'))
def raises_assertion(self, exception, call): return addimport(combine(exception, call, "assert_raises(%s, %s)"), ('nose.tools', 'assert_raises'))
def equal_assertion(self, expected, actual): return addimport(combine(expected, actual, "assert_equal(%s, %s)"), ('nose.tools', 'assert_equal'))
def generate_test_contents(events, template): contents = CodeString("") all_uncomplete = False already_assigned_names = {} for event in events: if isinstance(event, Assign): line = variable_assignment_line(event.name, event.obj, already_assigned_names) elif isinstance(event, BindingChange): if event.name.obj in already_assigned_names.keys(): already_assigned_names[ event.obj] = code_string_from_object_attribute_reference( event.name, already_assigned_names) continue # This is not a real test line, so just go directly to the next line. elif isinstance(event, EqualAssertionLine): expected = constructor_as_string(event.expected, already_assigned_names) if isinstance(event.actual, (Call, MethodCallContext)): actual = call_in_test(event.actual, already_assigned_names) elif isinstance(event.actual, ModuleVariableReference): actual = code_string_from_module_variable_reference( event.actual) elif isinstance(event.actual, ObjectAttributeReference): actual = code_string_from_object_attribute_reference( event.actual, already_assigned_names) elif isinstance(event.actual, str): actual = CodeString(event.actual) else: actual = constructor_as_string(event.actual, already_assigned_names) if expected.uncomplete: expected = type_as_string(event.expected) actual = type_of(actual) line = template.equal_assertion(expected, actual) elif isinstance(event, GeneratorAssertionLine): call = event.generator_call yields = generator_object_yields(call) expected = constructor_as_string(yields, already_assigned_names) actual = call_in_test(call, already_assigned_names) if expected.uncomplete: expected = type_as_string(yields) actual = map_types(actual) actual = addimport(actual, 'types') line = template.equal_assertion(expected, actual) elif isinstance(event, RaisesAssertionLine): actual = call_in_test(event.call, already_assigned_names) actual = in_lambda(actual) if is_serialized_string(event.expected_exception): exception = todo_value(event.expected_exception.reconstructor) else: exception = CodeString(event.expected_exception.type_name) exception = addimport(exception, event.expected_exception.type_import) line = template.raises_assertion(exception, actual) elif isinstance(event, CommentLine): line = CodeString(event.comment) elif isinstance(event, SkipTestLine): line = template.skip_test() elif isinstance(event, EqualAssertionStubLine): line = template.equal_assertion( CodeString('expected', uncomplete=True), event.actual) elif isinstance(event, BuiltinMethodWithPositionArgsSideEffect): # All objects affected by side effects are named. object_name = already_assigned_names[event.obj] line = call_as_string_for( "%s.%s" % (object_name, event.definition.name), event.args_mapping(), event.definition, already_assigned_names) elif isinstance(event, AttributeRebind): # All objects affected by side effects are named. object_name = already_assigned_names[event.obj] line = attribute_assignment_line( "%s.%s" % (object_name, event.name), event.value, already_assigned_names) else: raise TypeError( "Don't know how to generate test contents for event %r." % event) if line.uncomplete: all_uncomplete = True if all_uncomplete and not isinstance(event, SkipTestLine): line = combine("# ", line) contents = combine(contents, add_newline(line)) return contents
def constructor_as_string(object, assigned_names={}): """For a given object (either a SerializedObject or a list of them) return a string representing a code that will construct it. >>> from test.helper import make_fresh_serialize >>> serialize = make_fresh_serialize() >>> m = Module(None, 'myclasses') It handles built-in types >>> constructor_as_string(serialize(123)) '123' >>> constructor_as_string(serialize('string')) "'string'" >>> constructor_as_string([serialize(1), serialize('two')]) "[1, 'two']" as well as instances of user-defined classes >>> obj = UserObject(None, Class('SomeClass', module=m)) >>> constructor_as_string(obj) 'SomeClass()' interpreting their arguments correctly >>> obj.add_call(MethodCall(Method('__init__', ['self', 'arg']), {'arg': serialize('whatever')}, serialize(None))) >>> constructor_as_string(obj) "SomeClass('whatever')" even if they're user objects themselves: >>> otherobj = UserObject(None, Class('SomeOtherClass', module=m)) >>> otherobj.add_call(MethodCall(Method('__init__', ['self', 'object']), {'object': obj}, serialize(None))) >>> constructor_as_string(otherobj) "SomeOtherClass(SomeClass('whatever'))" or they are already named: >>> s = serialize("string") >>> anotherobj = UserObject(None, Class('AnotherClass', module=m)) >>> anotherobj.add_call(MethodCall(Method('__init__', ['self', 's']), {'s': s}, serialize(None))) >>> constructor_as_string(anotherobj, {s: 's'}) 'AnotherClass(s)' Handles composite objects: >>> constructor_as_string(serialize([1, "a", None])) "[1, 'a', None]" even when they contain instances of user-defined classes: >>> constructor_as_string(SequenceObject([obj], lambda x:x)) "[SomeClass('whatever')]" or other composite objects: >>> constructor_as_string(serialize((23, [4, [5]], {'a': 'b'}))) "(23, [4, [5]], {'a': 'b'})" or already named objects: >>> seq = serialize(["a", None]) >>> astring = seq.contained_objects[0] >>> constructor_as_string(seq, {astring: 'astring'}) '[astring, None]' Empty tuples are recreated properly: >>> constructor_as_string(serialize((((42,),),))) '(((42,),),)' Recreated objects keep their import information: >>> cs = constructor_as_string(UserObject(None, Class('MyClass', module=m))) >>> cs 'MyClass()' >>> cs.imports set([('myclasses', 'MyClass')]) Library objects like xml.dom.minidom.Element are recreated properly as well: >>> from xml.dom.minidom import Element >>> constructor_as_string(serialize(Element("tag", "uri", "prefix"))) "Element('tag', 'uri', 'prefix')" """ if isinstance(object, list): return list_of(map(constructor_as_string, object)) elif assigned_names.has_key(object): return CodeString(assigned_names[object]) elif isinstance(object, UserObject): # Look for __init__ call and base the constructor on that. init_call = object.get_init_call() if init_call: cs = call_as_string_for(object.klass.name, init_call.input, init_call.definition, assigned_names) else: cs = call_as_string(object.klass.name, {}) return addimport(cs, import_for(object.klass)) elif isinstance(object, ImmutableObject): return CodeString(object.reconstructor, imports=object.imports) elif isinstance(object, (CompositeObject, LibraryObject)): arguments = join(', ', get_contained_objects_info(object, assigned_names)) return putinto(arguments, object.constructor_format, object.imports) elif isinstance(object, GeneratorObject): if object.is_activated(): cs = call_as_string_for(object.definition.name, object.args, object.definition) return addimport(cs, import_for(object.definition)) else: return todo_value('generator') elif isinstance(object, UnknownObject): return todo_value(object.partial_reconstructor) else: raise TypeError("constructor_as_string expected SerializedObject at input, not %s" % object)
def constructor_as_string(object, assigned_names={}): """For a given object (either a SerializedObject or a list of them) return a string representing a code that will construct it. >>> from test.helper import make_fresh_serialize >>> serialize = make_fresh_serialize() >>> m = Module(None, 'myclasses') It handles built-in types >>> constructor_as_string(serialize(123)) '123' >>> constructor_as_string(serialize('string')) "'string'" >>> constructor_as_string([serialize(1), serialize('two')]) "[1, 'two']" as well as instances of user-defined classes >>> obj = UserObject(None, Class('SomeClass', module=m)) >>> constructor_as_string(obj) 'SomeClass()' interpreting their arguments correctly >>> obj.add_call(MethodCall(Method('__init__', ['self', 'arg']), {'arg': serialize('whatever')}, serialize(None))) >>> constructor_as_string(obj) "SomeClass('whatever')" even if they're user objects themselves: >>> otherobj = UserObject(None, Class('SomeOtherClass', module=m)) >>> otherobj.add_call(MethodCall(Method('__init__', ['self', 'object']), {'object': obj}, serialize(None))) >>> constructor_as_string(otherobj) "SomeOtherClass(SomeClass('whatever'))" or they are already named: >>> s = serialize("string") >>> anotherobj = UserObject(None, Class('AnotherClass', module=m)) >>> anotherobj.add_call(MethodCall(Method('__init__', ['self', 's']), {'s': s}, serialize(None))) >>> constructor_as_string(anotherobj, {s: 's'}) 'AnotherClass(s)' Handles composite objects: >>> constructor_as_string(serialize([1, "a", None])) "[1, 'a', None]" even when they contain instances of user-defined classes: >>> constructor_as_string(SequenceObject([obj], lambda x:x)) "[SomeClass('whatever')]" or other composite objects: >>> constructor_as_string(serialize((23, [4, [5]], {'a': 'b'}))) "(23, [4, [5]], {'a': 'b'})" or already named objects: >>> seq = serialize(["a", None]) >>> astring = seq.contained_objects[0] >>> constructor_as_string(seq, {astring: 'astring'}) '[astring, None]' Empty tuples are recreated properly: >>> constructor_as_string(serialize((((42,),),))) '(((42,),),)' Recreated objects keep their import information: >>> cs = constructor_as_string(UserObject(None, Class('MyClass', module=m))) >>> cs 'MyClass()' >>> cs.imports set([('myclasses', 'MyClass')]) Library objects like xml.dom.minidom.Element are recreated properly as well: >>> from xml.dom.minidom import Element >>> constructor_as_string(serialize(Element("tag", "uri", "prefix"))) "Element('tag', 'uri', 'prefix')" """ if isinstance(object, list): return list_of(map(constructor_as_string, object)) elif assigned_names.has_key(object): return CodeString(assigned_names[object]) elif isinstance(object, UserObject): # Look for __init__ call and base the constructor on that. init_call = object.get_init_call() if init_call: cs = call_as_string_for(object.klass.name, init_call.input, init_call.definition, assigned_names) else: cs = call_as_string(object.klass.name, {}) return addimport(cs, import_for(object.klass)) elif isinstance(object, ImmutableObject): return CodeString(object.reconstructor, imports=object.imports) elif isinstance(object, (CompositeObject, LibraryObject)): arguments = join(', ', get_contained_objects_info(object, assigned_names)) return putinto(arguments, object.constructor_format, object.imports) elif isinstance(object, GeneratorObject): if object.is_activated(): cs = call_as_string_for(object.definition.name, object.args, object.definition) return addimport(cs, import_for(object.definition)) else: return todo_value('generator') elif isinstance(object, UnknownObject): return todo_value(object.partial_reconstructor) else: raise TypeError( "constructor_as_string expected SerializedObject at input, not %s" % object)
def skip_test(self): return addimport(CodeString("raise SkipTest # TODO: implement your test here"), ('nose', 'SkipTest'))
def generate_test_contents(events, template): contents = CodeString("") all_uncomplete = False already_assigned_names = {} for event in events: if isinstance(event, Assign): line = variable_assignment_line(event.name, event.obj, already_assigned_names) elif isinstance(event, BindingChange): if event.name.obj in already_assigned_names.keys(): already_assigned_names[event.obj] = code_string_from_object_attribute_reference(event.name, already_assigned_names) continue # This is not a real test line, so just go directly to the next line. elif isinstance(event, EqualAssertionLine): expected = constructor_as_string(event.expected, already_assigned_names) if isinstance(event.actual, (Call, MethodCallContext)): actual = call_in_test(event.actual, already_assigned_names) elif isinstance(event.actual, ModuleVariableReference): actual = code_string_from_module_variable_reference(event.actual) elif isinstance(event.actual, ObjectAttributeReference): actual = code_string_from_object_attribute_reference(event.actual, already_assigned_names) elif isinstance(event.actual, str): actual = CodeString(event.actual) else: actual = constructor_as_string(event.actual, already_assigned_names) if expected.uncomplete: expected = type_as_string(event.expected) actual = type_of(actual) line = template.equal_assertion(expected, actual) elif isinstance(event, GeneratorAssertionLine): call = event.generator_call yields = generator_object_yields(call) expected = constructor_as_string(yields, already_assigned_names) actual = call_in_test(call, already_assigned_names) if expected.uncomplete: expected = type_as_string(yields) actual = map_types(actual) actual = addimport(actual, 'types') line = template.equal_assertion(expected, actual) elif isinstance(event, RaisesAssertionLine): actual = call_in_test(event.call, already_assigned_names) actual = in_lambda(actual) if is_serialized_string(event.expected_exception): exception = todo_value(event.expected_exception.reconstructor) else: exception = CodeString(event.expected_exception.type_name) exception = addimport(exception, event.expected_exception.type_import) line = template.raises_assertion(exception, actual) elif isinstance(event, CommentLine): line = CodeString(event.comment) elif isinstance(event, SkipTestLine): line = template.skip_test() elif isinstance(event, EqualAssertionStubLine): line = template.equal_assertion(CodeString('expected', uncomplete=True), event.actual) elif isinstance(event, BuiltinMethodWithPositionArgsSideEffect): # All objects affected by side effects are named. object_name = already_assigned_names[event.obj] line = call_as_string_for("%s.%s" % (object_name, event.definition.name), event.args_mapping(), event.definition, already_assigned_names) elif isinstance(event, AttributeRebind): # All objects affected by side effects are named. object_name = already_assigned_names[event.obj] line = attribute_assignment_line("%s.%s" % (object_name, event.name), event.value, already_assigned_names) else: raise TypeError("Don't know how to generate test contents for event %r." % event) if line.uncomplete: all_uncomplete = True if all_uncomplete and not isinstance(event, SkipTestLine): line = combine("# ", line) contents = combine(contents, add_newline(line)) return contents