<s> import re , sys <EOL> from difflib import unified_diff , ndiff <EOL> import pprint <EOL> import logging <EOL> import svntest <EOL> logger = logging . getLogger ( ) <EOL> class SVNUnexpectedOutput ( svntest . Failure ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNUnexpectedStdout ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNUnexpectedStderr ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNExpectedStdout ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNExpectedStderr ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNUnexpectedExitCode ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNIncorrectDatatype ( SVNUnexpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class SVNDumpParseError ( svntest . Failure ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> def createExpectedOutput ( expected , output_type , match_all = True ) : <EOL> """<STR_LIT>""" <EOL> if isinstance ( expected , list ) : <EOL> expected = ExpectedOutput ( expected ) <EOL> elif isinstance ( expected , str ) : <EOL> expected = RegexOutput ( expected , match_all ) <EOL> elif isinstance ( expected , int ) : <EOL> expected = RegexOutput ( "<STR_LIT>" % expected , False ) <EOL> elif expected is AnyOutput : <EOL> expected = AnyOutput ( ) <EOL> elif expected is not None and not isinstance ( expected , ExpectedOutput ) : <EOL> raise SVNIncorrectDatatype ( "<STR_LIT>" % output_type ) <EOL> return expected <EOL> class ExpectedOutput : <EOL> """<STR_LIT>""" <EOL> is_regex = False <EOL> is_unordered = False <EOL> def __init__ ( self , output , match_all = True ) : <EOL> """<STR_LIT>""" <EOL> self . output = output <EOL> self . match_all = match_all <EOL> def __str__ ( self ) : <EOL> return str ( self . output ) <EOL> def __cmp__ ( self , other ) : <EOL> raise Exception ( '<STR_LIT>' ) <EOL> def matches ( self , other , except_re = None ) : <EOL> """<STR_LIT>""" <EOL> if self . output is None : <EOL> expected = [ ] <EOL> else : <EOL> expected = self . output <EOL> if other is None : <EOL> actual = [ ] <EOL> else : <EOL> actual = other <EOL> if not isinstance ( actual , list ) : <EOL> actual = [ actual ] <EOL> if not isinstance ( expected , list ) : <EOL> expected = [ expected ] <EOL> if except_re : <EOL> return self . matches_except ( expected , actual , except_re ) <EOL> else : <EOL> return self . is_equivalent_list ( expected , actual ) <EOL> def matches_except ( self , expected , actual , except_re ) : <EOL> "<STR_LIT>" <EOL> if not self . is_regex : <EOL> i_expected = <NUM_LIT:0> <EOL> i_actual = <NUM_LIT:0> <EOL> while i_expected < len ( expected ) and i_actual < len ( actual ) : <EOL> if re . match ( except_re , actual [ i_actual ] ) : <EOL> i_actual += <NUM_LIT:1> <EOL> elif re . match ( except_re , expected [ i_expected ] ) : <EOL> i_expected += <NUM_LIT:1> <EOL> elif expected [ i_expected ] == actual [ i_actual ] : <EOL> i_expected += <NUM_LIT:1> <EOL> i_actual += <NUM_LIT:1> <EOL> else : <EOL> return False <EOL> if i_expected == len ( expected ) and i_actual == len ( actual ) : <EOL> return True <EOL> return False <EOL> else : <EOL> raise Exception ( "<STR_LIT>" ) <EOL> def is_equivalent_list ( self , expected , actual ) : <EOL> "<STR_LIT>" <EOL> if not self . is_regex : <EOL> if self . match_all : <EOL> return expected == actual <EOL> i_expected = <NUM_LIT:0> <EOL> for actual_line in actual : <EOL> if expected [ i_expected ] == actual_line : <EOL> i_expected += <NUM_LIT:1> <EOL> if i_expected == len ( expected ) : <EOL> return True <EOL> return False <EOL> expected_re = expected [ <NUM_LIT:0> ] <EOL> if self . match_all : <EOL> all_lines_match_re = True <EOL> else : <EOL> all_lines_match_re = False <EOL> if len ( actual ) == <NUM_LIT:0> : <EOL> return False <EOL> for actual_line in actual : <EOL> if self . match_all : <EOL> if not re . match ( expected_re , actual_line ) : <EOL> return False <EOL> else : <EOL> if re . match ( expected_re , actual_line ) : <EOL> return True <EOL> return all_lines_match_re <EOL> def display_differences ( self , message , label , actual ) : <EOL> """<STR_LIT>""" <EOL> display_lines ( message , label , self . output , actual , <EOL> self . is_regex , self . is_unordered ) <EOL> class AnyOutput ( ExpectedOutput ) : <EOL> def __init__ ( self ) : <EOL> ExpectedOutput . __init__ ( self , None , False ) <EOL> def is_equivalent_list ( self , ignored , actual ) : <EOL> if len ( actual ) == <NUM_LIT:0> : <EOL> return False <EOL> for line in actual : <EOL> if line : <EOL> return True <EOL> return False <EOL> def display_differences ( self , message , label , actual ) : <EOL> if message : <EOL> logger . warn ( message ) <EOL> class RegexOutput ( ExpectedOutput ) : <EOL> is_regex = True <EOL> class UnorderedOutput ( ExpectedOutput ) : <EOL> """<STR_LIT>""" <EOL> is_unordered = True <EOL> def __cmp__ ( self , other ) : <EOL> raise Exception ( '<STR_LIT>' ) <EOL> def matches_except ( self , expected , actual , except_re ) : <EOL> assert type ( actual ) == type ( [ ] ) <EOL> return self . is_equivalent_list ( [ l for l in expected if not except_re . match ( l ) ] , <EOL> [ l for l in actual if not except_re . match ( l ) ] ) <EOL> def is_equivalent_list ( self , expected , actual ) : <EOL> "<STR_LIT>" <EOL> e_set = set ( expected ) <EOL> a_set = set ( actual ) <EOL> if self . match_all : <EOL> if len ( e_set ) != len ( a_set ) : <EOL> return False <EOL> if self . is_regex : <EOL> for expect_re in e_set : <EOL> for actual_line in a_set : <EOL> if re . match ( expect_re , actual_line ) : <EOL> a_set . remove ( actual_line ) <EOL> break <EOL> else : <EOL> return False <EOL> return True <EOL> return e_set == a_set <EOL> if self . is_regex : <EOL> for expect_re in e_set : <EOL> for actual_line in a_set : <EOL> if re . match ( expect_re , actual_line ) : <EOL> return True <EOL> return False <EOL> return len ( e_set . intersection ( a_set ) ) > <NUM_LIT:0> <EOL> class UnorderedRegexOutput ( UnorderedOutput , RegexOutput ) : <EOL> is_regex = True <EOL> is_unordered = True <EOL> def display_trees ( message , label , expected , actual ) : <EOL> '<STR_LIT>' <EOL> if message is not None : <EOL> logger . warn ( message ) <EOL> if expected is not None : <EOL> logger . warn ( '<STR_LIT>' , label ) <EOL> svntest . tree . dump_tree ( expected ) <EOL> if actual is not None : <EOL> logger . warn ( '<STR_LIT>' , label ) <EOL> svntest . tree . dump_tree ( actual ) <EOL> def display_lines ( message , label , expected , actual , expected_is_regexp = None , <EOL> expected_is_unordered = None ) : <EOL> """<STR_LIT>""" <EOL> if message is not None : <EOL> logger . warn ( message ) <EOL> if expected is not None : <EOL> output = '<STR_LIT>' % label <EOL> if expected_is_regexp : <EOL> output += '<STR_LIT>' <EOL> expected = [ expected + '<STR_LIT:\n>' ] <EOL> if expected_is_unordered : <EOL> output += '<STR_LIT>' <EOL> output += '<STR_LIT::>' <EOL> logger . warn ( output ) <EOL> for x in expected : <EOL> sys . stdout . write ( x ) <EOL> if actual is not None : <EOL> logger . warn ( '<STR_LIT>' , label ) <EOL> for x in actual : <EOL> sys . stdout . write ( x ) <EOL> if not expected_is_regexp : <EOL> logger . warn ( '<STR_LIT>' + '<STR_LIT:U+0020>' . join ( output . split ( '<STR_LIT:U+0020>' ) [ <NUM_LIT:1> : ] ) ) <EOL> if type ( expected ) is str : <EOL> expected = [ expected ] <EOL> if type ( actual ) is str : <EOL> actual = [ actual ] <EOL> for x in unified_diff ( expected , actual , <EOL> fromfile = "<STR_LIT>" % label , <EOL> tofile = "<STR_LIT>" % label ) : <EOL> sys . stdout . write ( x ) <EOL> def compare_and_display_lines ( message , label , expected , actual , <EOL> raisable = None , except_re = None ) : <EOL> """<STR_LIT>""" <EOL> if raisable is None : <EOL> raisable = svntest . main . SVNLineUnequal <EOL> if not isinstance ( expected , ExpectedOutput ) : <EOL> expected = ExpectedOutput ( expected ) <EOL> if isinstance ( actual , str ) : <EOL> actual = [ actual ] <EOL> actual = [ line for line in actual if not line . startswith ( '<STR_LIT>' ) ] <EOL> if not expected . matches ( actual , except_re ) : <EOL> expected . display_differences ( message , label , actual ) <EOL> raise raisable <EOL> def verify_outputs ( message , actual_stdout , actual_stderr , <EOL> expected_stdout , expected_stderr , all_stdout = True ) : <EOL> """<STR_LIT>""" <EOL> expected_stderr = createExpectedOutput ( expected_stderr , '<STR_LIT>' , False ) <EOL> expected_stdout = createExpectedOutput ( expected_stdout , '<STR_LIT>' , all_stdout ) <EOL> for ( actual , expected , label , raisable ) in ( <EOL> ( actual_stderr , expected_stderr , '<STR_LIT>' , SVNExpectedStderr ) , <EOL> ( actual_stdout , expected_stdout , '<STR_LIT>' , SVNExpectedStdout ) ) : <EOL> if expected is None : <EOL> continue <EOL> if isinstance ( expected , RegexOutput ) : <EOL> raisable = svntest . main . SVNUnmatchedError <EOL> elif not isinstance ( expected , AnyOutput ) : <EOL> raisable = svntest . main . SVNLineUnequal <EOL> compare_and_display_lines ( message , label , expected , actual , raisable ) <EOL> def verify_exit_code ( message , actual , expected , <EOL> raisable = SVNUnexpectedExitCode ) : <EOL> """<STR_LIT>""" <EOL> if expected != actual : <EOL> display_lines ( message , "<STR_LIT>" , <EOL> str ( expected ) + '<STR_LIT:\n>' , str ( actual ) + '<STR_LIT:\n>' ) <EOL> raise raisable <EOL> class DumpParser : <EOL> def __init__ ( self , lines ) : <EOL> self . current = <NUM_LIT:0> <EOL> self . lines = lines <EOL> self . parsed = { } <EOL> def parse_line ( self , regex , required = True ) : <EOL> m = re . match ( regex , self . lines [ self . current ] ) <EOL> if not m : <EOL> if required : <EOL> raise SVNDumpParseError ( "<STR_LIT>" <EOL> % ( regex , self . current , <EOL> self . lines [ self . current ] ) ) <EOL> else : <EOL> return None <EOL> self . current += <NUM_LIT:1> <EOL> return m . group ( <NUM_LIT:1> ) <EOL> def parse_blank ( self , required = True ) : <EOL> if self . lines [ self . current ] != '<STR_LIT:\n>' : <EOL> if required : <EOL> raise SVNDumpParseError ( "<STR_LIT>" <EOL> % ( self . current , self . lines [ self . current ] ) ) <EOL> else : <EOL> return False <EOL> self . current += <NUM_LIT:1> <EOL> return True <EOL> def parse_format ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' ) <EOL> def parse_uuid ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' ) <EOL> def parse_revision ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' ) <EOL> def parse_prop_length ( self , required = True ) : <EOL> return self . parse_line ( '<STR_LIT>' , required ) <EOL> def parse_content_length ( self , required = True ) : <EOL> return self . parse_line ( '<STR_LIT>' , required ) <EOL> def parse_path ( self ) : <EOL> path = self . parse_line ( '<STR_LIT>' , required = False ) <EOL> if not path and self . lines [ self . current ] == '<STR_LIT>' : <EOL> self . current += <NUM_LIT:1> <EOL> path = '<STR_LIT>' <EOL> return path <EOL> def parse_kind ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_action ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' ) <EOL> def parse_copyfrom_rev ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_copyfrom_path ( self ) : <EOL> path = self . parse_line ( '<STR_LIT>' , required = False ) <EOL> if not path and self . lines [ self . current ] == '<STR_LIT>' : <EOL> self . current += <NUM_LIT:1> <EOL> path = '<STR_LIT>' <EOL> return path <EOL> def parse_copy_md5 ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_copy_sha1 ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_text_md5 ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_text_sha1 ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def parse_text_length ( self ) : <EOL> return self . parse_line ( '<STR_LIT>' , required = False ) <EOL> def get_props ( self ) : <EOL> props = [ ] <EOL> while not re . match ( '<STR_LIT>' , self . lines [ self . current ] ) : <EOL> props . append ( self . lines [ self . current ] ) <EOL> self . current += <NUM_LIT:1> <EOL> self . current += <NUM_LIT:1> <EOL> return props <EOL> def get_content ( self , length ) : <EOL> content = '<STR_LIT>' <EOL> while len ( content ) < length : <EOL> content += self . lines [ self . current ] <EOL> self . current += <NUM_LIT:1> <EOL> if len ( content ) == length + <NUM_LIT:1> : <EOL> content = content [ : - <NUM_LIT:1> ] <EOL> elif len ( content ) != length : <EOL> raise SVNDumpParseError ( "<STR_LIT>" <EOL> % ( length , len ( content ) , self . current ) ) <EOL> return content <EOL> def parse_one_node ( self ) : <EOL> node = { } <EOL> node [ '<STR_LIT>' ] = self . parse_kind ( ) <EOL> action = self . parse_action ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_copyfrom_rev ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_copyfrom_path ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_copy_md5 ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_copy_sha1 ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_prop_length ( required = False ) <EOL> node [ '<STR_LIT>' ] = self . parse_text_length ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_text_md5 ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_text_sha1 ( ) <EOL> node [ '<STR_LIT>' ] = self . parse_content_length ( required = False ) <EOL> self . parse_blank ( ) <EOL> if node [ '<STR_LIT>' ] : <EOL> node [ '<STR_LIT>' ] = self . get_props ( ) <EOL> if node [ '<STR_LIT>' ] : <EOL> node [ '<STR_LIT:content>' ] = self . get_content ( int ( node [ '<STR_LIT>' ] ) ) <EOL> blanks = <NUM_LIT:0> <EOL> while self . current < len ( self . lines ) and self . parse_blank ( required = False ) : <EOL> blanks += <NUM_LIT:1> <EOL> node [ '<STR_LIT>' ] = blanks <EOL> return action , node <EOL> def parse_all_nodes ( self ) : <EOL> nodes = { } <EOL> while True : <EOL> if self . current >= len ( self . lines ) : <EOL> break <EOL> path = self . parse_path ( ) <EOL> if not path and not path is '<STR_LIT>' : <EOL> break <EOL> if not nodes . get ( path ) : <EOL> nodes [ path ] = { } <EOL> action , node = self . parse_one_node ( ) <EOL> if nodes [ path ] . get ( action ) : <EOL> raise SVNDumpParseError ( "<STR_LIT>" <EOL> % ( action , path , self . current ) ) <EOL> nodes [ path ] [ action ] = node <EOL> return nodes <EOL> def parse_one_revision ( self ) : <EOL> revision = { } <EOL> number = self . parse_revision ( ) <EOL> revision [ '<STR_LIT>' ] = self . parse_prop_length ( ) <EOL> revision [ '<STR_LIT>' ] = self . parse_content_length ( ) <EOL> self . parse_blank ( ) <EOL> revision [ '<STR_LIT>' ] = self . get_props ( ) <EOL> self . parse_blank ( ) <EOL> revision [ '<STR_LIT>' ] = self . parse_all_nodes ( ) <EOL> return number , revision <EOL> def parse_all_revisions ( self ) : <EOL> while self . current < len ( self . lines ) : <EOL> number , revision = self . parse_one_revision ( ) <EOL> if self . parsed . get ( number ) : <EOL> raise SVNDumpParseError ( "<STR_LIT>" <EOL> % ( number , self . current ) ) <EOL> self . parsed [ number ] = revision <EOL> def parse ( self ) : <EOL> self . parsed [ '<STR_LIT>' ] = self . parse_format ( ) <EOL> self . parse_blank ( ) <EOL> self . parsed [ '<STR_LIT>' ] = self . parse_uuid ( ) <EOL> self . parse_blank ( ) <EOL> self . parse_all_revisions ( ) <EOL> return self . parsed <EOL> def compare_dump_files ( message , label , expected , actual ) : <EOL> """<STR_LIT>""" <EOL> parsed_expected = DumpParser ( expected ) . parse ( ) <EOL> parsed_actual = DumpParser ( actual ) . parse ( ) <EOL> if parsed_expected != parsed_actual : <EOL> raise svntest . Failure ( '<STR_LIT:\n>' + '<STR_LIT:\n>' . join ( ndiff ( <EOL> pprint . pformat ( parsed_expected ) . splitlines ( ) , <EOL> pprint . pformat ( parsed_actual ) . splitlines ( ) ) ) ) </s>
