tests/test-manifest.py
changeset 43076 2372284d9457
parent 41676 0531dff73d0b
child 43949 8b1a9ba375e5
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    18 HASH_2 = b'f' * 40
    18 HASH_2 = b'f' * 40
    19 BIN_HASH_2 = binascii.unhexlify(HASH_2)
    19 BIN_HASH_2 = binascii.unhexlify(HASH_2)
    20 HASH_3 = b'1234567890abcdef0987654321deadbeef0fcafe'
    20 HASH_3 = b'1234567890abcdef0987654321deadbeef0fcafe'
    21 BIN_HASH_3 = binascii.unhexlify(HASH_3)
    21 BIN_HASH_3 = binascii.unhexlify(HASH_3)
    22 A_SHORT_MANIFEST = (
    22 A_SHORT_MANIFEST = (
    23     b'bar/baz/qux.py\0%(hash2)s%(flag2)s\n'
    23     b'bar/baz/qux.py\0%(hash2)s%(flag2)s\n' b'foo\0%(hash1)s%(flag1)s\n'
    24     b'foo\0%(hash1)s%(flag1)s\n'
    24 ) % {b'hash1': HASH_1, b'flag1': b'', b'hash2': HASH_2, b'flag2': b'l',}
    25     ) % {b'hash1': HASH_1,
       
    26          b'flag1': b'',
       
    27          b'hash2': HASH_2,
       
    28          b'flag2': b'l',
       
    29          }
       
    30 
    25 
    31 A_DEEPER_MANIFEST = (
    26 A_DEEPER_MANIFEST = (
    32     b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
    27     b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
    33     b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
    28     b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
    34     b'a/b/c/foo.py\0%(hash3)s%(flag1)s\n'
    29     b'a/b/c/foo.py\0%(hash3)s%(flag1)s\n'
    45     b'a/d/pizza.py\0%(hash3)s%(flag2)s\n'
    40     b'a/d/pizza.py\0%(hash3)s%(flag2)s\n'
    46     b'a/green.py\0%(hash1)s%(flag2)s\n'
    41     b'a/green.py\0%(hash1)s%(flag2)s\n'
    47     b'a/purple.py\0%(hash2)s%(flag1)s\n'
    42     b'a/purple.py\0%(hash2)s%(flag1)s\n'
    48     b'app.py\0%(hash3)s%(flag1)s\n'
    43     b'app.py\0%(hash3)s%(flag1)s\n'
    49     b'readme.txt\0%(hash2)s%(flag1)s\n'
    44     b'readme.txt\0%(hash2)s%(flag1)s\n'
    50     ) % {b'hash1': HASH_1,
    45 ) % {
    51          b'flag1': b'',
    46     b'hash1': HASH_1,
    52          b'hash2': HASH_2,
    47     b'flag1': b'',
    53          b'flag2': b'l',
    48     b'hash2': HASH_2,
    54          b'hash3': HASH_3,
    49     b'flag2': b'l',
    55          }
    50     b'hash3': HASH_3,
       
    51 }
    56 
    52 
    57 HUGE_MANIFEST_ENTRIES = 200001
    53 HUGE_MANIFEST_ENTRIES = 200001
    58 
    54 
    59 izip = getattr(itertools, 'izip', zip)
    55 izip = getattr(itertools, 'izip', zip)
    60 if 'xrange' not in globals():
    56 if 'xrange' not in globals():
    61     xrange = range
    57     xrange = range
    62 
    58 
    63 A_HUGE_MANIFEST = b''.join(sorted(
    59 A_HUGE_MANIFEST = b''.join(
    64     b'file%d\0%s%s\n' % (i, h, f) for i, h, f in
    60     sorted(
    65     izip(xrange(200001),
    61         b'file%d\0%s%s\n' % (i, h, f)
    66          itertools.cycle((HASH_1, HASH_2)),
    62         for i, h, f in izip(
    67          itertools.cycle((b'', b'x', b'l')))))
    63             xrange(200001),
       
    64             itertools.cycle((HASH_1, HASH_2)),
       
    65             itertools.cycle((b'', b'x', b'l')),
       
    66         )
       
    67     )
       
    68 )
       
    69 
    68 
    70 
    69 class basemanifesttests(object):
    71 class basemanifesttests(object):
    70     def parsemanifest(self, text):
    72     def parsemanifest(self, text):
    71         raise NotImplementedError('parsemanifest not implemented by test case')
    73         raise NotImplementedError('parsemanifest not implemented by test case')
    72 
    74 
    95         self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
    97         self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
    96 
    98 
    97         m = self.parsemanifest(A_SHORT_MANIFEST)
    99         m = self.parsemanifest(A_SHORT_MANIFEST)
    98         m[b'a'] = want
   100         m[b'a'] = want
    99         self.assertEqual(want, m[b'a'])
   101         self.assertEqual(want, m[b'a'])
   100         self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST,
   102         self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST, m.text())
   101                          m.text())
       
   102 
   103 
   103     def testSetFlag(self):
   104     def testSetFlag(self):
   104         want = b'x'
   105         want = b'x'
   105 
   106 
   106         m = self.parsemanifest(EMTPY_MANIFEST)
   107         m = self.parsemanifest(EMTPY_MANIFEST)
   113         m = self.parsemanifest(A_SHORT_MANIFEST)
   114         m = self.parsemanifest(A_SHORT_MANIFEST)
   114         # first add a file; a file-less flag makes no sense
   115         # first add a file; a file-less flag makes no sense
   115         m[b'a'] = BIN_HASH_1
   116         m[b'a'] = BIN_HASH_1
   116         m.setflag(b'a', want)
   117         m.setflag(b'a', want)
   117         self.assertEqual(want, m.flags(b'a'))
   118         self.assertEqual(want, m.flags(b'a'))
   118         self.assertEqual(b'a\0' + HASH_1 + want + b'\n' + A_SHORT_MANIFEST,
   119         self.assertEqual(
   119                          m.text())
   120             b'a\0' + HASH_1 + want + b'\n' + A_SHORT_MANIFEST, m.text()
       
   121         )
   120 
   122 
   121     def testCopy(self):
   123     def testCopy(self):
   122         m = self.parsemanifest(A_SHORT_MANIFEST)
   124         m = self.parsemanifest(A_SHORT_MANIFEST)
   123         m[b'a'] = BIN_HASH_1
   125         m[b'a'] = BIN_HASH_1
   124         m2 = m.copy()
   126         m2 = m.copy()
   125         del m
   127         del m
   126         del m2 # make sure we don't double free() anything
   128         del m2  # make sure we don't double free() anything
   127 
   129 
   128     def testCompaction(self):
   130     def testCompaction(self):
   129         unhex = binascii.unhexlify
   131         unhex = binascii.unhexlify
   130         h1, h2 = unhex(HASH_1), unhex(HASH_2)
   132         h1, h2 = unhex(HASH_1), unhex(HASH_2)
   131         m = self.parsemanifest(A_SHORT_MANIFEST)
   133         m = self.parsemanifest(A_SHORT_MANIFEST)
   132         m[b'alpha'] = h1
   134         m[b'alpha'] = h1
   133         m[b'beta'] = h2
   135         m[b'beta'] = h2
   134         del m[b'foo']
   136         del m[b'foo']
   135         want = b'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
   137         want = b'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
   136             HASH_1, HASH_2, HASH_2)
   138             HASH_1,
       
   139             HASH_2,
       
   140             HASH_2,
       
   141         )
   137         self.assertEqual(want, m.text())
   142         self.assertEqual(want, m.text())
   138         self.assertEqual(3, len(m))
   143         self.assertEqual(3, len(m))
   139         self.assertEqual([b'alpha', b'bar/baz/qux.py', b'beta'], list(m))
   144         self.assertEqual([b'alpha', b'bar/baz/qux.py', b'beta'], list(m))
   140         self.assertEqual(h1, m[b'alpha'])
   145         self.assertEqual(h1, m[b'alpha'])
   141         self.assertEqual(h2, m[b'bar/baz/qux.py'])
   146         self.assertEqual(h2, m[b'bar/baz/qux.py'])
   153         f = m.flags(b'foo')
   158         f = m.flags(b'foo')
   154         want = h + b'a'
   159         want = h + b'a'
   155         # Merge code wants to set 21-byte fake hashes at times
   160         # Merge code wants to set 21-byte fake hashes at times
   156         m[b'foo'] = want
   161         m[b'foo'] = want
   157         self.assertEqual(want, m[b'foo'])
   162         self.assertEqual(want, m[b'foo'])
   158         self.assertEqual([(b'bar/baz/qux.py', BIN_HASH_2),
   163         self.assertEqual(
   159                           (b'foo', BIN_HASH_1 + b'a')],
   164             [(b'bar/baz/qux.py', BIN_HASH_2), (b'foo', BIN_HASH_1 + b'a')],
   160                          list(m.items()))
   165             list(m.items()),
       
   166         )
   161         # Sometimes it even tries a 22-byte fake hash, but we can
   167         # Sometimes it even tries a 22-byte fake hash, but we can
   162         # return 21 and it'll work out
   168         # return 21 and it'll work out
   163         m[b'foo'] = want + b'+'
   169         m[b'foo'] = want + b'+'
   164         self.assertEqual(want, m[b'foo'])
   170         self.assertEqual(want, m[b'foo'])
   165         # make sure the suffix survives a copy
   171         # make sure the suffix survives a copy
   168         self.assertEqual(want, m2[b'foo'])
   174         self.assertEqual(want, m2[b'foo'])
   169         self.assertEqual(1, len(m2))
   175         self.assertEqual(1, len(m2))
   170         m2 = m.copy()
   176         m2 = m.copy()
   171         self.assertEqual(want, m2[b'foo'])
   177         self.assertEqual(want, m2[b'foo'])
   172         # suffix with iteration
   178         # suffix with iteration
   173         self.assertEqual([(b'bar/baz/qux.py', BIN_HASH_2),
   179         self.assertEqual(
   174                           (b'foo', want)],
   180             [(b'bar/baz/qux.py', BIN_HASH_2), (b'foo', want)], list(m.items())
   175                          list(m.items()))
   181         )
   176 
   182 
   177         # shows up in diff
   183         # shows up in diff
   178         self.assertEqual({b'foo': ((want, f), (h, b''))}, m.diff(clean))
   184         self.assertEqual({b'foo': ((want, f), (h, b''))}, m.diff(clean))
   179         self.assertEqual({b'foo': ((h, b''), (want, f))}, clean.diff(m))
   185         self.assertEqual({b'foo': ((h, b''), (want, f))}, clean.diff(m))
   180 
   186 
   181     def testMatchException(self):
   187     def testMatchException(self):
   182         m = self.parsemanifest(A_SHORT_MANIFEST)
   188         m = self.parsemanifest(A_SHORT_MANIFEST)
   183         match = matchmod.match(b'', b'', [b're:.*'])
   189         match = matchmod.match(b'', b'', [b're:.*'])
       
   190 
   184         def filt(path):
   191         def filt(path):
   185             if path == b'foo':
   192             if path == b'foo':
   186                 assert False
   193                 assert False
   187             return True
   194             return True
       
   195 
   188         match.matchfn = filt
   196         match.matchfn = filt
   189         with self.assertRaises(AssertionError):
   197         with self.assertRaises(AssertionError):
   190             m.matches(match)
   198             m.matches(match)
   191 
   199 
   192     def testRemoveItem(self):
   200     def testRemoveItem(self):
   204     def testManifestDiff(self):
   212     def testManifestDiff(self):
   205         MISSING = (None, b'')
   213         MISSING = (None, b'')
   206         addl = b'z-only-in-left\0' + HASH_1 + b'\n'
   214         addl = b'z-only-in-left\0' + HASH_1 + b'\n'
   207         addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
   215         addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
   208         left = self.parsemanifest(
   216         left = self.parsemanifest(
   209             A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl)
   217             A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl
       
   218         )
   210         right = self.parsemanifest(A_SHORT_MANIFEST + addr)
   219         right = self.parsemanifest(A_SHORT_MANIFEST + addr)
   211         want = {
   220         want = {
   212             b'foo': ((BIN_HASH_3, b'x'),
   221             b'foo': ((BIN_HASH_3, b'x'), (BIN_HASH_1, b'')),
   213                      (BIN_HASH_1, b'')),
       
   214             b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
   222             b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
   215             b'z-only-in-right': (MISSING, (BIN_HASH_2, b'x')),
   223             b'z-only-in-right': (MISSING, (BIN_HASH_2, b'x')),
   216             }
   224         }
   217         self.assertEqual(want, left.diff(right))
   225         self.assertEqual(want, left.diff(right))
   218 
   226 
   219         want = {
   227         want = {
   220             b'bar/baz/qux.py': (MISSING, (BIN_HASH_2, b'l')),
   228             b'bar/baz/qux.py': (MISSING, (BIN_HASH_2, b'l')),
   221             b'foo': (MISSING, (BIN_HASH_3, b'x')),
   229             b'foo': (MISSING, (BIN_HASH_3, b'x')),
   222             b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
   230             b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
   223             }
   231         }
   224         self.assertEqual(want, self.parsemanifest(EMTPY_MANIFEST).diff(left))
   232         self.assertEqual(want, self.parsemanifest(EMTPY_MANIFEST).diff(left))
   225 
   233 
   226         want = {
   234         want = {
   227             b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
   235             b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
   228             b'foo': ((BIN_HASH_3, b'x'), MISSING),
   236             b'foo': ((BIN_HASH_3, b'x'), MISSING),
   229             b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
   237             b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
   230             }
   238         }
   231         self.assertEqual(want, left.diff(self.parsemanifest(EMTPY_MANIFEST)))
   239         self.assertEqual(want, left.diff(self.parsemanifest(EMTPY_MANIFEST)))
   232         copy = right.copy()
   240         copy = right.copy()
   233         del copy[b'z-only-in-right']
   241         del copy[b'z-only-in-right']
   234         del right[b'foo']
   242         del right[b'foo']
   235         want = {
   243         want = {
   236             b'foo': (MISSING, (BIN_HASH_1, b'')),
   244             b'foo': (MISSING, (BIN_HASH_1, b'')),
   237             b'z-only-in-right': ((BIN_HASH_2, b'x'), MISSING),
   245             b'z-only-in-right': ((BIN_HASH_2, b'x'), MISSING),
   238             }
   246         }
   239         self.assertEqual(want, right.diff(copy))
   247         self.assertEqual(want, right.diff(copy))
   240 
   248 
   241         short = self.parsemanifest(A_SHORT_MANIFEST)
   249         short = self.parsemanifest(A_SHORT_MANIFEST)
   242         pruned = short.copy()
   250         pruned = short.copy()
   243         del pruned[b'foo']
   251         del pruned[b'foo']
   244         want = {
   252         want = {
   245             b'foo': ((BIN_HASH_1, b''), MISSING),
   253             b'foo': ((BIN_HASH_1, b''), MISSING),
   246             }
   254         }
   247         self.assertEqual(want, short.diff(pruned))
   255         self.assertEqual(want, short.diff(pruned))
   248         want = {
   256         want = {
   249             b'foo': (MISSING, (BIN_HASH_1, b'')),
   257             b'foo': (MISSING, (BIN_HASH_1, b'')),
   250             }
   258         }
   251         self.assertEqual(want, pruned.diff(short))
   259         self.assertEqual(want, pruned.diff(short))
   252         want = {
   260         want = {
   253             b'bar/baz/qux.py': None,
   261             b'bar/baz/qux.py': None,
   254             b'foo': (MISSING, (BIN_HASH_1, b'')),
   262             b'foo': (MISSING, (BIN_HASH_1, b'')),
   255             }
   263         }
   256         self.assertEqual(want, pruned.diff(short, clean=True))
   264         self.assertEqual(want, pruned.diff(short, clean=True))
   257 
   265 
   258     def testReversedLines(self):
   266     def testReversedLines(self):
   259         backwards = b''.join(
   267         backwards = b''.join(
   260             l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l)
   268             l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l
       
   269         )
   261         try:
   270         try:
   262             self.parsemanifest(backwards)
   271             self.parsemanifest(backwards)
   263             self.fail('Should have raised ValueError')
   272             self.fail('Should have raised ValueError')
   264         except ValueError as v:
   273         except ValueError as v:
   265             self.assertIn('Manifest lines not in sorted order.', str(v))
   274             self.assertIn('Manifest lines not in sorted order.', str(v))
   290         m = self.parsemanifest(A_HUGE_MANIFEST)
   299         m = self.parsemanifest(A_HUGE_MANIFEST)
   291 
   300 
   292         match = matchmod.exact([b'file1', b'file200', b'file300'])
   301         match = matchmod.exact([b'file1', b'file200', b'file300'])
   293         m2 = m.matches(match)
   302         m2 = m.matches(match)
   294 
   303 
   295         w = (b'file1\0%sx\n'
   304         w = (b'file1\0%sx\n' b'file200\0%sl\n' b'file300\0%s\n') % (
   296              b'file200\0%sl\n'
   305             HASH_2,
   297              b'file300\0%s\n') % (HASH_2, HASH_1, HASH_1)
   306             HASH_1,
       
   307             HASH_1,
       
   308         )
   298         self.assertEqual(w, m2.text())
   309         self.assertEqual(w, m2.text())
   299 
   310 
   300     def testMatchesNonexistentFile(self):
   311     def testMatchesNonexistentFile(self):
   301         '''Tests matches() for a small set of specific files, including one
   312         '''Tests matches() for a small set of specific files, including one
   302         nonexistent file to make sure in only matches against existing files.
   313         nonexistent file to make sure in only matches against existing files.
   303         '''
   314         '''
   304         m = self.parsemanifest(A_DEEPER_MANIFEST)
   315         m = self.parsemanifest(A_DEEPER_MANIFEST)
   305 
   316 
   306         match = matchmod.exact([b'a/b/c/bar.txt', b'a/b/d/qux.py',
   317         match = matchmod.exact(
   307                                 b'readme.txt', b'nonexistent'])
   318             [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt', b'nonexistent']
   308         m2 = m.matches(match)
   319         )
   309 
   320         m2 = m.matches(match)
   310         self.assertEqual(
   321 
   311                 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt'],
   322         self.assertEqual(
   312                 m2.keys())
   323             [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt'], m2.keys()
       
   324         )
   313 
   325 
   314     def testMatchesNonexistentDirectory(self):
   326     def testMatchesNonexistentDirectory(self):
   315         '''Tests matches() for a relpath match on a directory that doesn't
   327         '''Tests matches() for a relpath match on a directory that doesn't
   316         actually exist.'''
   328         actually exist.'''
   317         m = self.parsemanifest(A_DEEPER_MANIFEST)
   329         m = self.parsemanifest(A_DEEPER_MANIFEST)
   347         m = self.parsemanifest(A_DEEPER_MANIFEST)
   359         m = self.parsemanifest(A_DEEPER_MANIFEST)
   348 
   360 
   349         match = matchmod.match(b'/', b'', [b'a/b'], default=b'relpath')
   361         match = matchmod.match(b'/', b'', [b'a/b'], default=b'relpath')
   350         m2 = m.matches(match)
   362         m2 = m.matches(match)
   351 
   363 
   352         self.assertEqual([
   364         self.assertEqual(
   353             b'a/b/c/bar.py', b'a/b/c/bar.txt', b'a/b/c/foo.py',
   365             [
   354             b'a/b/c/foo.txt',
   366                 b'a/b/c/bar.py',
   355             b'a/b/d/baz.py', b'a/b/d/qux.py', b'a/b/d/ten.txt', b'a/b/dog.py',
   367                 b'a/b/c/bar.txt',
   356             b'a/b/fish.py'], m2.keys())
   368                 b'a/b/c/foo.py',
       
   369                 b'a/b/c/foo.txt',
       
   370                 b'a/b/d/baz.py',
       
   371                 b'a/b/d/qux.py',
       
   372                 b'a/b/d/ten.txt',
       
   373                 b'a/b/dog.py',
       
   374                 b'a/b/fish.py',
       
   375             ],
       
   376             m2.keys(),
       
   377         )
   357 
   378 
   358     def testMatchesExactPath(self):
   379     def testMatchesExactPath(self):
   359         '''Tests matches() on an exact match on a directory, which should
   380         '''Tests matches() on an exact match on a directory, which should
   360         result in an empty manifest because you can't perform an exact match
   381         result in an empty manifest because you can't perform an exact match
   361         against a directory.'''
   382         against a directory.'''
   372         m = self.parsemanifest(A_DEEPER_MANIFEST)
   393         m = self.parsemanifest(A_DEEPER_MANIFEST)
   373 
   394 
   374         match = matchmod.match(b'/', b'a/b', [b'.'], default=b'relpath')
   395         match = matchmod.match(b'/', b'a/b', [b'.'], default=b'relpath')
   375         m2 = m.matches(match)
   396         m2 = m.matches(match)
   376 
   397 
   377         self.assertEqual([
   398         self.assertEqual(
   378             b'a/b/c/bar.py', b'a/b/c/bar.txt', b'a/b/c/foo.py',
   399             [
   379             b'a/b/c/foo.txt', b'a/b/d/baz.py', b'a/b/d/qux.py',
   400                 b'a/b/c/bar.py',
   380             b'a/b/d/ten.txt', b'a/b/dog.py', b'a/b/fish.py'], m2.keys())
   401                 b'a/b/c/bar.txt',
       
   402                 b'a/b/c/foo.py',
       
   403                 b'a/b/c/foo.txt',
       
   404                 b'a/b/d/baz.py',
       
   405                 b'a/b/d/qux.py',
       
   406                 b'a/b/d/ten.txt',
       
   407                 b'a/b/dog.py',
       
   408                 b'a/b/fish.py',
       
   409             ],
       
   410             m2.keys(),
       
   411         )
   381 
   412 
   382     def testMatchesWithPattern(self):
   413     def testMatchesWithPattern(self):
   383         '''Tests matches() for files matching a pattern that reside
   414         '''Tests matches() for files matching a pattern that reside
   384         deeper than the specified directory.'''
   415         deeper than the specified directory.'''
   385         m = self.parsemanifest(A_DEEPER_MANIFEST)
   416         m = self.parsemanifest(A_DEEPER_MANIFEST)
   386 
   417 
   387         match = matchmod.match(b'/', b'', [b'a/b/*/*.txt'])
   418         match = matchmod.match(b'/', b'', [b'a/b/*/*.txt'])
   388         m2 = m.matches(match)
   419         m2 = m.matches(match)
   389 
   420 
   390         self.assertEqual(
   421         self.assertEqual(
   391                 [b'a/b/c/bar.txt', b'a/b/c/foo.txt', b'a/b/d/ten.txt'],
   422             [b'a/b/c/bar.txt', b'a/b/c/foo.txt', b'a/b/d/ten.txt'], m2.keys()
   392                 m2.keys())
   423         )
       
   424 
   393 
   425 
   394 class testmanifestdict(unittest.TestCase, basemanifesttests):
   426 class testmanifestdict(unittest.TestCase, basemanifesttests):
   395     def parsemanifest(self, text):
   427     def parsemanifest(self, text):
   396         return manifestmod.manifestdict(text)
   428         return manifestmod.manifestdict(text)
   397 
   429 
   412             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   444             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   413             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   445             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   414             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   446             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   415             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   447             b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
   416             b'\x00\x00\xc0\x8aey\x1d}\x01\xd8\xe0\xb9\xf3\xde\x1b\xcf\x17'
   448             b'\x00\x00\xc0\x8aey\x1d}\x01\xd8\xe0\xb9\xf3\xde\x1b\xcf\x17'
   417             b'\xac\xbe')
   449             b'\xac\xbe'
       
   450         )
   418         with self.assertRaises(ValueError):
   451         with self.assertRaises(ValueError):
   419             self.parsemanifest(data)
   452             self.parsemanifest(data)
       
   453 
   420 
   454 
   421 class testtreemanifest(unittest.TestCase, basemanifesttests):
   455 class testtreemanifest(unittest.TestCase, basemanifesttests):
   422     def parsemanifest(self, text):
   456     def parsemanifest(self, text):
   423         return manifestmod.treemanifest(b'', text)
   457         return manifestmod.treemanifest(b'', text)
   424 
   458 
   425     def testWalkSubtrees(self):
   459     def testWalkSubtrees(self):
   426         m = self.parsemanifest(A_DEEPER_MANIFEST)
   460         m = self.parsemanifest(A_DEEPER_MANIFEST)
   427 
   461 
   428         dirs = [s._dir for s in m.walksubtrees()]
   462         dirs = [s._dir for s in m.walksubtrees()]
   429         self.assertEqual(
   463         self.assertEqual(
   430             sorted([
   464             sorted(
   431                 b'', b'a/', b'a/c/', b'a/d/', b'a/b/', b'a/b/c/', b'a/b/d/']),
   465                 [b'', b'a/', b'a/c/', b'a/d/', b'a/b/', b'a/b/c/', b'a/b/d/']
   432             sorted(dirs)
   466             ),
       
   467             sorted(dirs),
   433         )
   468         )
   434 
   469 
   435         match = matchmod.match(b'/', b'', [b'path:a/b/'])
   470         match = matchmod.match(b'/', b'', [b'path:a/b/'])
   436         dirs = [s._dir for s in m.walksubtrees(matcher=match)]
   471         dirs = [s._dir for s in m.walksubtrees(matcher=match)]
   437         self.assertEqual(
   472         self.assertEqual(sorted([b'a/b/', b'a/b/c/', b'a/b/d/']), sorted(dirs))
   438             sorted([b'a/b/', b'a/b/c/', b'a/b/d/']),
   473 
   439             sorted(dirs)
       
   440         )
       
   441 
   474 
   442 if __name__ == '__main__':
   475 if __name__ == '__main__':
   443     silenttestrunner.main(__name__)
   476     silenttestrunner.main(__name__)