mercurial/testing/storage.py
changeset 39772 ae531f5e583c
child 39776 cb65d4b7e429
equal deleted inserted replaced
39771:a063786c89fb 39772:ae531f5e583c
       
     1 # storage.py - Testing of storage primitives.
       
     2 #
       
     3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
       
     4 #
       
     5 # This software may be used and distributed according to the terms of the
       
     6 # GNU General Public License version 2 or any later version.
       
     7 
       
     8 from __future__ import absolute_import
       
     9 
       
    10 import unittest
       
    11 
       
    12 from ..node import (
       
    13     hex,
       
    14     nullid,
       
    15     nullrev,
       
    16 )
       
    17 from .. import (
       
    18     error,
       
    19     mdiff,
       
    20     revlog,
       
    21 )
       
    22 
       
    23 class basetestcase(unittest.TestCase):
       
    24     if not getattr(unittest.TestCase, r'assertRaisesRegex', False):
       
    25         assertRaisesRegex = (# camelcase-required
       
    26             unittest.TestCase.assertRaisesRegexp)
       
    27 
       
    28 class revisiondeltarequest(object):
       
    29     def __init__(self, node, p1, p2, linknode, basenode, ellipsis):
       
    30         self.node = node
       
    31         self.p1node = p1
       
    32         self.p2node = p2
       
    33         self.linknode = linknode
       
    34         self.basenode = basenode
       
    35         self.ellipsis = ellipsis
       
    36 
       
    37 class ifileindextests(basetestcase):
       
    38     """Generic tests for the ifileindex interface.
       
    39 
       
    40     All file storage backends for index data should conform to the tests in this
       
    41     class.
       
    42 
       
    43     Use ``makeifileindextests()`` to create an instance of this type.
       
    44     """
       
    45     def testempty(self):
       
    46         f = self._makefilefn()
       
    47         self.assertEqual(len(f), 0, 'new file store has 0 length by default')
       
    48         self.assertEqual(list(f), [], 'iter yields nothing by default')
       
    49 
       
    50         gen = iter(f)
       
    51         with self.assertRaises(StopIteration):
       
    52             next(gen)
       
    53 
       
    54         # revs() should evaluate to an empty list.
       
    55         self.assertEqual(list(f.revs()), [])
       
    56 
       
    57         revs = iter(f.revs())
       
    58         with self.assertRaises(StopIteration):
       
    59             next(revs)
       
    60 
       
    61         self.assertEqual(list(f.revs(start=20)), [])
       
    62 
       
    63         # parents() and parentrevs() work with nullid/nullrev.
       
    64         self.assertEqual(f.parents(nullid), (nullid, nullid))
       
    65         self.assertEqual(f.parentrevs(nullrev), (nullrev, nullrev))
       
    66 
       
    67         with self.assertRaises(error.LookupError):
       
    68             f.parents(b'\x01' * 20)
       
    69 
       
    70         for i in range(-5, 5):
       
    71             if i == nullrev:
       
    72                 continue
       
    73 
       
    74             with self.assertRaises(IndexError):
       
    75                 f.parentrevs(i)
       
    76 
       
    77         # nullid/nullrev lookup always works.
       
    78         self.assertEqual(f.rev(nullid), nullrev)
       
    79         self.assertEqual(f.node(nullrev), nullid)
       
    80 
       
    81         with self.assertRaises(error.LookupError):
       
    82             f.rev(b'\x01' * 20)
       
    83 
       
    84         for i in range(-5, 5):
       
    85             if i == nullrev:
       
    86                 continue
       
    87 
       
    88             with self.assertRaises(IndexError):
       
    89                 f.node(i)
       
    90 
       
    91         self.assertEqual(f.lookup(nullid), nullid)
       
    92         self.assertEqual(f.lookup(nullrev), nullid)
       
    93         self.assertEqual(f.lookup(hex(nullid)), nullid)
       
    94 
       
    95         # String converted to integer doesn't work for nullrev.
       
    96         with self.assertRaises(error.LookupError):
       
    97             f.lookup(b'%d' % nullrev)
       
    98 
       
    99         self.assertEqual(f.linkrev(nullrev), nullrev)
       
   100 
       
   101         for i in range(-5, 5):
       
   102             if i == nullrev:
       
   103                 continue
       
   104 
       
   105             with self.assertRaises(IndexError):
       
   106                 f.linkrev(i)
       
   107 
       
   108         self.assertEqual(f.flags(nullrev), 0)
       
   109 
       
   110         for i in range(-5, 5):
       
   111             if i == nullrev:
       
   112                 continue
       
   113 
       
   114             with self.assertRaises(IndexError):
       
   115                 f.flags(i)
       
   116 
       
   117         self.assertFalse(f.iscensored(nullrev))
       
   118 
       
   119         for i in range(-5, 5):
       
   120             if i == nullrev:
       
   121                 continue
       
   122 
       
   123             with self.assertRaises(IndexError):
       
   124                 f.iscensored(i)
       
   125 
       
   126         self.assertEqual(list(f.commonancestorsheads(nullid, nullid)), [])
       
   127 
       
   128         with self.assertRaises(ValueError):
       
   129             self.assertEqual(list(f.descendants([])), [])
       
   130 
       
   131         self.assertEqual(list(f.descendants([nullrev])), [])
       
   132 
       
   133         self.assertEqual(f.headrevs(), [nullrev])
       
   134         self.assertEqual(f.heads(), [nullid])
       
   135         self.assertEqual(f.heads(nullid), [nullid])
       
   136         self.assertEqual(f.heads(None, [nullid]), [nullid])
       
   137         self.assertEqual(f.heads(nullid, [nullid]), [nullid])
       
   138 
       
   139         self.assertEqual(f.children(nullid), [])
       
   140 
       
   141         with self.assertRaises(error.LookupError):
       
   142             f.children(b'\x01' * 20)
       
   143 
       
   144         self.assertEqual(f.deltaparent(nullrev), nullrev)
       
   145 
       
   146         for i in range(-5, 5):
       
   147             if i == nullrev:
       
   148                 continue
       
   149 
       
   150             with self.assertRaises(IndexError):
       
   151                 f.deltaparent(i)
       
   152 
       
   153     def testsinglerevision(self):
       
   154         f = self._makefilefn()
       
   155         with self._maketransactionfn() as tr:
       
   156             node = f.add(b'initial', None, tr, 0, nullid, nullid)
       
   157 
       
   158         self.assertEqual(len(f), 1)
       
   159         self.assertEqual(list(f), [0])
       
   160 
       
   161         gen = iter(f)
       
   162         self.assertEqual(next(gen), 0)
       
   163 
       
   164         with self.assertRaises(StopIteration):
       
   165             next(gen)
       
   166 
       
   167         self.assertEqual(list(f.revs()), [0])
       
   168         self.assertEqual(list(f.revs(start=1)), [])
       
   169         self.assertEqual(list(f.revs(start=0)), [0])
       
   170         self.assertEqual(list(f.revs(stop=0)), [0])
       
   171         self.assertEqual(list(f.revs(stop=1)), [0])
       
   172         self.assertEqual(list(f.revs(1, 1)), [])
       
   173         # TODO buggy
       
   174         self.assertEqual(list(f.revs(1, 0)), [1, 0])
       
   175         self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
       
   176 
       
   177         self.assertEqual(f.parents(node), (nullid, nullid))
       
   178         self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
       
   179 
       
   180         with self.assertRaises(error.LookupError):
       
   181             f.parents(b'\x01' * 20)
       
   182 
       
   183         with self.assertRaises(IndexError):
       
   184             f.parentrevs(1)
       
   185 
       
   186         self.assertEqual(f.rev(node), 0)
       
   187 
       
   188         with self.assertRaises(error.LookupError):
       
   189             f.rev(b'\x01' * 20)
       
   190 
       
   191         self.assertEqual(f.node(0), node)
       
   192 
       
   193         with self.assertRaises(IndexError):
       
   194             f.node(1)
       
   195 
       
   196         self.assertEqual(f.lookup(node), node)
       
   197         self.assertEqual(f.lookup(0), node)
       
   198         self.assertEqual(f.lookup(b'0'), node)
       
   199         self.assertEqual(f.lookup(hex(node)), node)
       
   200 
       
   201         self.assertEqual(f.linkrev(0), 0)
       
   202 
       
   203         with self.assertRaises(IndexError):
       
   204             f.linkrev(1)
       
   205 
       
   206         self.assertEqual(f.flags(0), 0)
       
   207 
       
   208         with self.assertRaises(IndexError):
       
   209             f.flags(1)
       
   210 
       
   211         self.assertFalse(f.iscensored(0))
       
   212 
       
   213         with self.assertRaises(IndexError):
       
   214             f.iscensored(1)
       
   215 
       
   216         self.assertEqual(list(f.descendants([0])), [])
       
   217 
       
   218         self.assertEqual(f.headrevs(), [0])
       
   219 
       
   220         self.assertEqual(f.heads(), [node])
       
   221         self.assertEqual(f.heads(node), [node])
       
   222         self.assertEqual(f.heads(stop=[node]), [node])
       
   223 
       
   224         with self.assertRaises(error.LookupError):
       
   225             f.heads(stop=[b'\x01' * 20])
       
   226 
       
   227         self.assertEqual(f.children(node), [])
       
   228 
       
   229         self.assertEqual(f.deltaparent(0), nullrev)
       
   230 
       
   231     def testmultiplerevisions(self):
       
   232         fulltext0 = b'x' * 1024
       
   233         fulltext1 = fulltext0 + b'y'
       
   234         fulltext2 = b'y' + fulltext0 + b'z'
       
   235 
       
   236         f = self._makefilefn()
       
   237         with self._maketransactionfn() as tr:
       
   238             node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
       
   239             node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
       
   240             node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
       
   241 
       
   242         self.assertEqual(len(f), 3)
       
   243         self.assertEqual(list(f), [0, 1, 2])
       
   244 
       
   245         gen = iter(f)
       
   246         self.assertEqual(next(gen), 0)
       
   247         self.assertEqual(next(gen), 1)
       
   248         self.assertEqual(next(gen), 2)
       
   249 
       
   250         with self.assertRaises(StopIteration):
       
   251             next(gen)
       
   252 
       
   253         self.assertEqual(list(f.revs()), [0, 1, 2])
       
   254         self.assertEqual(list(f.revs(0)), [0, 1, 2])
       
   255         self.assertEqual(list(f.revs(1)), [1, 2])
       
   256         self.assertEqual(list(f.revs(2)), [2])
       
   257         self.assertEqual(list(f.revs(3)), [])
       
   258         self.assertEqual(list(f.revs(stop=1)), [0, 1])
       
   259         self.assertEqual(list(f.revs(stop=2)), [0, 1, 2])
       
   260         self.assertEqual(list(f.revs(stop=3)), [0, 1, 2])
       
   261         self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
       
   262         self.assertEqual(list(f.revs(2, 1)), [2, 1])
       
   263         # TODO this is wrong
       
   264         self.assertEqual(list(f.revs(3, 2)), [3, 2])
       
   265 
       
   266         self.assertEqual(f.parents(node0), (nullid, nullid))
       
   267         self.assertEqual(f.parents(node1), (node0, nullid))
       
   268         self.assertEqual(f.parents(node2), (node1, nullid))
       
   269 
       
   270         self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
       
   271         self.assertEqual(f.parentrevs(1), (0, nullrev))
       
   272         self.assertEqual(f.parentrevs(2), (1, nullrev))
       
   273 
       
   274         self.assertEqual(f.rev(node0), 0)
       
   275         self.assertEqual(f.rev(node1), 1)
       
   276         self.assertEqual(f.rev(node2), 2)
       
   277 
       
   278         with self.assertRaises(error.LookupError):
       
   279             f.rev(b'\x01' * 20)
       
   280 
       
   281         self.assertEqual(f.node(0), node0)
       
   282         self.assertEqual(f.node(1), node1)
       
   283         self.assertEqual(f.node(2), node2)
       
   284 
       
   285         with self.assertRaises(IndexError):
       
   286             f.node(3)
       
   287 
       
   288         self.assertEqual(f.lookup(node0), node0)
       
   289         self.assertEqual(f.lookup(0), node0)
       
   290         self.assertEqual(f.lookup(b'0'), node0)
       
   291         self.assertEqual(f.lookup(hex(node0)), node0)
       
   292 
       
   293         self.assertEqual(f.lookup(node1), node1)
       
   294         self.assertEqual(f.lookup(1), node1)
       
   295         self.assertEqual(f.lookup(b'1'), node1)
       
   296         self.assertEqual(f.lookup(hex(node1)), node1)
       
   297 
       
   298         self.assertEqual(f.linkrev(0), 0)
       
   299         self.assertEqual(f.linkrev(1), 1)
       
   300         self.assertEqual(f.linkrev(2), 3)
       
   301 
       
   302         with self.assertRaises(IndexError):
       
   303             f.linkrev(3)
       
   304 
       
   305         self.assertEqual(f.flags(0), 0)
       
   306         self.assertEqual(f.flags(1), 0)
       
   307         self.assertEqual(f.flags(2), 0)
       
   308 
       
   309         with self.assertRaises(IndexError):
       
   310             f.flags(3)
       
   311 
       
   312         self.assertFalse(f.iscensored(0))
       
   313         self.assertFalse(f.iscensored(1))
       
   314         self.assertFalse(f.iscensored(2))
       
   315 
       
   316         with self.assertRaises(IndexError):
       
   317             f.iscensored(3)
       
   318 
       
   319         self.assertEqual(f.commonancestorsheads(node1, nullid), [])
       
   320         self.assertEqual(f.commonancestorsheads(node1, node0), [node0])
       
   321         self.assertEqual(f.commonancestorsheads(node1, node1), [node1])
       
   322         self.assertEqual(f.commonancestorsheads(node0, node1), [node0])
       
   323         self.assertEqual(f.commonancestorsheads(node1, node2), [node1])
       
   324         self.assertEqual(f.commonancestorsheads(node2, node1), [node1])
       
   325 
       
   326         self.assertEqual(list(f.descendants([0])), [1, 2])
       
   327         self.assertEqual(list(f.descendants([1])), [2])
       
   328         self.assertEqual(list(f.descendants([0, 1])), [1, 2])
       
   329 
       
   330         self.assertEqual(f.headrevs(), [2])
       
   331 
       
   332         self.assertEqual(f.heads(), [node2])
       
   333         self.assertEqual(f.heads(node0), [node2])
       
   334         self.assertEqual(f.heads(node1), [node2])
       
   335         self.assertEqual(f.heads(node2), [node2])
       
   336 
       
   337         # TODO this behavior seems wonky. Is it correct? If so, the
       
   338         # docstring for heads() should be updated to reflect desired
       
   339         # behavior.
       
   340         self.assertEqual(f.heads(stop=[node1]), [node1, node2])
       
   341         self.assertEqual(f.heads(stop=[node0]), [node0, node2])
       
   342         self.assertEqual(f.heads(stop=[node1, node2]), [node1, node2])
       
   343 
       
   344         with self.assertRaises(error.LookupError):
       
   345             f.heads(stop=[b'\x01' * 20])
       
   346 
       
   347         self.assertEqual(f.children(node0), [node1])
       
   348         self.assertEqual(f.children(node1), [node2])
       
   349         self.assertEqual(f.children(node2), [])
       
   350 
       
   351         self.assertEqual(f.deltaparent(0), nullrev)
       
   352         self.assertEqual(f.deltaparent(1), 0)
       
   353         self.assertEqual(f.deltaparent(2), 1)
       
   354 
       
   355     def testmultipleheads(self):
       
   356         f = self._makefilefn()
       
   357 
       
   358         with self._maketransactionfn() as tr:
       
   359             node0 = f.add(b'0', None, tr, 0, nullid, nullid)
       
   360             node1 = f.add(b'1', None, tr, 1, node0, nullid)
       
   361             node2 = f.add(b'2', None, tr, 2, node1, nullid)
       
   362             node3 = f.add(b'3', None, tr, 3, node0, nullid)
       
   363             node4 = f.add(b'4', None, tr, 4, node3, nullid)
       
   364             node5 = f.add(b'5', None, tr, 5, node0, nullid)
       
   365 
       
   366         self.assertEqual(len(f), 6)
       
   367 
       
   368         self.assertEqual(list(f.descendants([0])), [1, 2, 3, 4, 5])
       
   369         self.assertEqual(list(f.descendants([1])), [2])
       
   370         self.assertEqual(list(f.descendants([2])), [])
       
   371         self.assertEqual(list(f.descendants([3])), [4])
       
   372         self.assertEqual(list(f.descendants([0, 1])), [1, 2, 3, 4, 5])
       
   373         self.assertEqual(list(f.descendants([1, 3])), [2, 4])
       
   374 
       
   375         self.assertEqual(f.headrevs(), [2, 4, 5])
       
   376 
       
   377         self.assertEqual(f.heads(), [node2, node4, node5])
       
   378         self.assertEqual(f.heads(node0), [node2, node4, node5])
       
   379         self.assertEqual(f.heads(node1), [node2])
       
   380         self.assertEqual(f.heads(node2), [node2])
       
   381         self.assertEqual(f.heads(node3), [node4])
       
   382         self.assertEqual(f.heads(node4), [node4])
       
   383         self.assertEqual(f.heads(node5), [node5])
       
   384 
       
   385         # TODO this seems wrong.
       
   386         self.assertEqual(f.heads(stop=[node0]), [node0, node2, node4, node5])
       
   387         self.assertEqual(f.heads(stop=[node1]), [node1, node2, node4, node5])
       
   388 
       
   389         self.assertEqual(f.children(node0), [node1, node3, node5])
       
   390         self.assertEqual(f.children(node1), [node2])
       
   391         self.assertEqual(f.children(node2), [])
       
   392         self.assertEqual(f.children(node3), [node4])
       
   393         self.assertEqual(f.children(node4), [])
       
   394         self.assertEqual(f.children(node5), [])
       
   395 
       
   396 class ifiledatatests(basetestcase):
       
   397     """Generic tests for the ifiledata interface.
       
   398 
       
   399     All file storage backends for data should conform to the tests in this
       
   400     class.
       
   401 
       
   402     Use ``makeifiledatatests()`` to create an instance of this type.
       
   403     """
       
   404     def testempty(self):
       
   405         f = self._makefilefn()
       
   406 
       
   407         self.assertEqual(f.rawsize(nullrev), 0)
       
   408 
       
   409         for i in range(-5, 5):
       
   410             if i == nullrev:
       
   411                 continue
       
   412 
       
   413             with self.assertRaises(IndexError):
       
   414                 f.rawsize(i)
       
   415 
       
   416         self.assertEqual(f.size(nullrev), 0)
       
   417 
       
   418         for i in range(-5, 5):
       
   419             if i == nullrev:
       
   420                 continue
       
   421 
       
   422             with self.assertRaises(IndexError):
       
   423                 f.size(i)
       
   424 
       
   425         with self.assertRaises(error.RevlogError):
       
   426             f.checkhash(b'', nullid)
       
   427 
       
   428         with self.assertRaises(error.LookupError):
       
   429             f.checkhash(b'', b'\x01' * 20)
       
   430 
       
   431         self.assertEqual(f.revision(nullid), b'')
       
   432         self.assertEqual(f.revision(nullid, raw=True), b'')
       
   433 
       
   434         with self.assertRaises(error.LookupError):
       
   435             f.revision(b'\x01' * 20)
       
   436 
       
   437         self.assertEqual(f.read(nullid), b'')
       
   438 
       
   439         with self.assertRaises(error.LookupError):
       
   440             f.read(b'\x01' * 20)
       
   441 
       
   442         self.assertFalse(f.renamed(nullid))
       
   443 
       
   444         with self.assertRaises(error.LookupError):
       
   445             f.read(b'\x01' * 20)
       
   446 
       
   447         self.assertTrue(f.cmp(nullid, b''))
       
   448         self.assertTrue(f.cmp(nullid, b'foo'))
       
   449 
       
   450         with self.assertRaises(error.LookupError):
       
   451             f.cmp(b'\x01' * 20, b'irrelevant')
       
   452 
       
   453         self.assertEqual(f.revdiff(nullrev, nullrev), b'')
       
   454 
       
   455         with self.assertRaises(IndexError):
       
   456             f.revdiff(0, nullrev)
       
   457 
       
   458         with self.assertRaises(IndexError):
       
   459             f.revdiff(nullrev, 0)
       
   460 
       
   461         with self.assertRaises(IndexError):
       
   462             f.revdiff(0, 0)
       
   463 
       
   464         gen = f.emitrevisiondeltas([])
       
   465         with self.assertRaises(StopIteration):
       
   466             next(gen)
       
   467 
       
   468         requests = [
       
   469             revisiondeltarequest(nullid, nullid, nullid, nullid, nullid, False),
       
   470         ]
       
   471         gen = f.emitrevisiondeltas(requests)
       
   472 
       
   473         delta = next(gen)
       
   474 
       
   475         self.assertEqual(delta.node, nullid)
       
   476         self.assertEqual(delta.p1node, nullid)
       
   477         self.assertEqual(delta.p2node, nullid)
       
   478         self.assertEqual(delta.linknode, nullid)
       
   479         self.assertEqual(delta.basenode, nullid)
       
   480         self.assertIsNone(delta.baserevisionsize)
       
   481         self.assertEqual(delta.revision, b'')
       
   482         self.assertIsNone(delta.delta)
       
   483 
       
   484         with self.assertRaises(StopIteration):
       
   485             next(gen)
       
   486 
       
   487         requests = [
       
   488             revisiondeltarequest(nullid, nullid, nullid, nullid, nullid, False),
       
   489             revisiondeltarequest(nullid, b'\x01' * 20, b'\x02' * 20,
       
   490                                  b'\x03' * 20, nullid, False)
       
   491         ]
       
   492 
       
   493         gen = f.emitrevisiondeltas(requests)
       
   494 
       
   495         next(gen)
       
   496         delta = next(gen)
       
   497 
       
   498         self.assertEqual(delta.node, nullid)
       
   499         self.assertEqual(delta.p1node, b'\x01' * 20)
       
   500         self.assertEqual(delta.p2node, b'\x02' * 20)
       
   501         self.assertEqual(delta.linknode, b'\x03' * 20)
       
   502         self.assertEqual(delta.basenode, nullid)
       
   503         self.assertIsNone(delta.baserevisionsize)
       
   504         self.assertEqual(delta.revision, b'')
       
   505         self.assertIsNone(delta.delta)
       
   506 
       
   507         with self.assertRaises(StopIteration):
       
   508             next(gen)
       
   509 
       
   510     def testsinglerevision(self):
       
   511         fulltext = b'initial'
       
   512 
       
   513         f = self._makefilefn()
       
   514         with self._maketransactionfn() as tr:
       
   515             node = f.add(fulltext, None, tr, 0, nullid, nullid)
       
   516 
       
   517         self.assertEqual(f.rawsize(0), len(fulltext))
       
   518 
       
   519         with self.assertRaises(IndexError):
       
   520             f.rawsize(1)
       
   521 
       
   522         self.assertEqual(f.size(0), len(fulltext))
       
   523 
       
   524         with self.assertRaises(IndexError):
       
   525             f.size(1)
       
   526 
       
   527         f.checkhash(fulltext, node)
       
   528         f.checkhash(fulltext, node, nullid, nullid)
       
   529 
       
   530         with self.assertRaises(error.RevlogError):
       
   531             f.checkhash(fulltext + b'extra', node)
       
   532 
       
   533         with self.assertRaises(error.RevlogError):
       
   534             f.checkhash(fulltext, node, b'\x01' * 20, nullid)
       
   535 
       
   536         with self.assertRaises(error.RevlogError):
       
   537             f.checkhash(fulltext, node, nullid, b'\x01' * 20)
       
   538 
       
   539         self.assertEqual(f.revision(node), fulltext)
       
   540         self.assertEqual(f.revision(node, raw=True), fulltext)
       
   541 
       
   542         self.assertEqual(f.read(node), fulltext)
       
   543 
       
   544         self.assertFalse(f.renamed(node))
       
   545 
       
   546         self.assertFalse(f.cmp(node, fulltext))
       
   547         self.assertTrue(f.cmp(node, fulltext + b'extra'))
       
   548 
       
   549         self.assertEqual(f.revdiff(0, 0), b'')
       
   550         self.assertEqual(f.revdiff(nullrev, 0),
       
   551                          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07%s' %
       
   552                          fulltext)
       
   553 
       
   554         self.assertEqual(f.revdiff(0, nullrev),
       
   555                          b'\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00')
       
   556 
       
   557         requests = [
       
   558             revisiondeltarequest(node, nullid, nullid, nullid, nullid, False),
       
   559         ]
       
   560         gen = f.emitrevisiondeltas(requests)
       
   561 
       
   562         delta = next(gen)
       
   563 
       
   564         self.assertEqual(delta.node, node)
       
   565         self.assertEqual(delta.p1node, nullid)
       
   566         self.assertEqual(delta.p2node, nullid)
       
   567         self.assertEqual(delta.linknode, nullid)
       
   568         self.assertEqual(delta.basenode, nullid)
       
   569         self.assertIsNone(delta.baserevisionsize)
       
   570         self.assertEqual(delta.revision, fulltext)
       
   571         self.assertIsNone(delta.delta)
       
   572 
       
   573         with self.assertRaises(StopIteration):
       
   574             next(gen)
       
   575 
       
   576     def testmultiplerevisions(self):
       
   577         fulltext0 = b'x' * 1024
       
   578         fulltext1 = fulltext0 + b'y'
       
   579         fulltext2 = b'y' + fulltext0 + b'z'
       
   580 
       
   581         f = self._makefilefn()
       
   582         with self._maketransactionfn() as tr:
       
   583             node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
       
   584             node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
       
   585             node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
       
   586 
       
   587         self.assertEqual(f.rawsize(0), len(fulltext0))
       
   588         self.assertEqual(f.rawsize(1), len(fulltext1))
       
   589         self.assertEqual(f.rawsize(2), len(fulltext2))
       
   590 
       
   591         with self.assertRaises(IndexError):
       
   592             f.rawsize(3)
       
   593 
       
   594         self.assertEqual(f.size(0), len(fulltext0))
       
   595         self.assertEqual(f.size(1), len(fulltext1))
       
   596         self.assertEqual(f.size(2), len(fulltext2))
       
   597 
       
   598         with self.assertRaises(IndexError):
       
   599             f.size(3)
       
   600 
       
   601         f.checkhash(fulltext0, node0)
       
   602         f.checkhash(fulltext1, node1)
       
   603         f.checkhash(fulltext1, node1, node0, nullid)
       
   604         f.checkhash(fulltext2, node2, node1, nullid)
       
   605 
       
   606         with self.assertRaises(error.RevlogError):
       
   607             f.checkhash(fulltext1, b'\x01' * 20)
       
   608 
       
   609         with self.assertRaises(error.RevlogError):
       
   610             f.checkhash(fulltext1 + b'extra', node1, node0, nullid)
       
   611 
       
   612         with self.assertRaises(error.RevlogError):
       
   613             f.checkhash(fulltext1, node1, node0, node0)
       
   614 
       
   615         self.assertEqual(f.revision(node0), fulltext0)
       
   616         self.assertEqual(f.revision(node0, raw=True), fulltext0)
       
   617         self.assertEqual(f.revision(node1), fulltext1)
       
   618         self.assertEqual(f.revision(node1, raw=True), fulltext1)
       
   619         self.assertEqual(f.revision(node2), fulltext2)
       
   620         self.assertEqual(f.revision(node2, raw=True), fulltext2)
       
   621 
       
   622         with self.assertRaises(error.LookupError):
       
   623             f.revision(b'\x01' * 20)
       
   624 
       
   625         self.assertEqual(f.read(node0), fulltext0)
       
   626         self.assertEqual(f.read(node1), fulltext1)
       
   627         self.assertEqual(f.read(node2), fulltext2)
       
   628 
       
   629         with self.assertRaises(error.LookupError):
       
   630             f.read(b'\x01' * 20)
       
   631 
       
   632         self.assertFalse(f.renamed(node0))
       
   633         self.assertFalse(f.renamed(node1))
       
   634         self.assertFalse(f.renamed(node2))
       
   635 
       
   636         with self.assertRaises(error.LookupError):
       
   637             f.renamed(b'\x01' * 20)
       
   638 
       
   639         self.assertFalse(f.cmp(node0, fulltext0))
       
   640         self.assertFalse(f.cmp(node1, fulltext1))
       
   641         self.assertFalse(f.cmp(node2, fulltext2))
       
   642 
       
   643         self.assertTrue(f.cmp(node1, fulltext0))
       
   644         self.assertTrue(f.cmp(node2, fulltext1))
       
   645 
       
   646         with self.assertRaises(error.LookupError):
       
   647             f.cmp(b'\x01' * 20, b'irrelevant')
       
   648 
       
   649         self.assertEqual(f.revdiff(0, 1),
       
   650                          b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
       
   651                          fulltext1)
       
   652 
       
   653         self.assertEqual(f.revdiff(0, 2),
       
   654                          b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x02' +
       
   655                          fulltext2)
       
   656 
       
   657         requests = [
       
   658             revisiondeltarequest(node0, nullid, nullid, b'\x01' * 20, nullid,
       
   659                                  False),
       
   660             revisiondeltarequest(node1, node0, nullid, b'\x02' * 20, node0,
       
   661                                  False),
       
   662             revisiondeltarequest(node2, node1, nullid, b'\x03' * 20, node1,
       
   663                                  False),
       
   664         ]
       
   665         gen = f.emitrevisiondeltas(requests)
       
   666 
       
   667         delta = next(gen)
       
   668 
       
   669         self.assertEqual(delta.node, node0)
       
   670         self.assertEqual(delta.p1node, nullid)
       
   671         self.assertEqual(delta.p2node, nullid)
       
   672         self.assertEqual(delta.linknode, b'\x01' * 20)
       
   673         self.assertEqual(delta.basenode, nullid)
       
   674         self.assertIsNone(delta.baserevisionsize)
       
   675         self.assertEqual(delta.revision, fulltext0)
       
   676         self.assertIsNone(delta.delta)
       
   677 
       
   678         delta = next(gen)
       
   679 
       
   680         self.assertEqual(delta.node, node1)
       
   681         self.assertEqual(delta.p1node, node0)
       
   682         self.assertEqual(delta.p2node, nullid)
       
   683         self.assertEqual(delta.linknode, b'\x02' * 20)
       
   684         self.assertEqual(delta.basenode, node0)
       
   685         self.assertIsNone(delta.baserevisionsize)
       
   686         self.assertIsNone(delta.revision)
       
   687         self.assertEqual(delta.delta,
       
   688                          b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
       
   689                          fulltext1)
       
   690 
       
   691         delta = next(gen)
       
   692 
       
   693         self.assertEqual(delta.node, node2)
       
   694         self.assertEqual(delta.p1node, node1)
       
   695         self.assertEqual(delta.p2node, nullid)
       
   696         self.assertEqual(delta.linknode, b'\x03' * 20)
       
   697         self.assertEqual(delta.basenode, node1)
       
   698         self.assertIsNone(delta.baserevisionsize)
       
   699         self.assertIsNone(delta.revision)
       
   700         self.assertEqual(delta.delta,
       
   701                          b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
       
   702                          fulltext2)
       
   703 
       
   704         with self.assertRaises(StopIteration):
       
   705             next(gen)
       
   706 
       
   707     def testrenamed(self):
       
   708         fulltext0 = b'foo'
       
   709         fulltext1 = b'bar'
       
   710         fulltext2 = b'baz'
       
   711 
       
   712         meta1 = {
       
   713             b'copy': b'source0',
       
   714             b'copyrev': b'a' * 40,
       
   715         }
       
   716 
       
   717         meta2 = {
       
   718             b'copy': b'source1',
       
   719             b'copyrev': b'b' * 40,
       
   720         }
       
   721 
       
   722         stored1 = b''.join([
       
   723             b'\x01\ncopy: source0\n',
       
   724             b'copyrev: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\x01\n',
       
   725             fulltext1,
       
   726         ])
       
   727 
       
   728         stored2 = b''.join([
       
   729             b'\x01\ncopy: source1\n',
       
   730             b'copyrev: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n\x01\n',
       
   731             fulltext2,
       
   732         ])
       
   733 
       
   734         f = self._makefilefn()
       
   735         with self._maketransactionfn() as tr:
       
   736             node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
       
   737             node1 = f.add(fulltext1, meta1, tr, 1, node0, nullid)
       
   738             node2 = f.add(fulltext2, meta2, tr, 2, nullid, nullid)
       
   739 
       
   740         self.assertEqual(f.rawsize(1), len(stored1))
       
   741         self.assertEqual(f.rawsize(2), len(stored2))
       
   742 
       
   743         # Metadata header isn't recognized when parent isn't nullid.
       
   744         self.assertEqual(f.size(1), len(stored1))
       
   745         self.assertEqual(f.size(2), len(fulltext2))
       
   746 
       
   747         self.assertEqual(f.revision(node1), stored1)
       
   748         self.assertEqual(f.revision(node1, raw=True), stored1)
       
   749         self.assertEqual(f.revision(node2), stored2)
       
   750         self.assertEqual(f.revision(node2, raw=True), stored2)
       
   751 
       
   752         self.assertEqual(f.read(node1), fulltext1)
       
   753         self.assertEqual(f.read(node2), fulltext2)
       
   754 
       
   755         # Returns False when first parent is set.
       
   756         self.assertFalse(f.renamed(node1))
       
   757         self.assertEqual(f.renamed(node2), (b'source1', b'\xbb' * 20))
       
   758 
       
   759         self.assertTrue(f.cmp(node1, fulltext1))
       
   760         self.assertTrue(f.cmp(node1, stored1))
       
   761         self.assertFalse(f.cmp(node2, fulltext2))
       
   762         self.assertTrue(f.cmp(node2, stored2))
       
   763 
       
   764     def testmetadataprefix(self):
       
   765         # Content with metadata prefix has extra prefix inserted in storage.
       
   766         fulltext0 = b'\x01\nfoo'
       
   767         stored0 = b'\x01\n\x01\n\x01\nfoo'
       
   768 
       
   769         fulltext1 = b'\x01\nbar'
       
   770         meta1 = {
       
   771             b'copy': b'source0',
       
   772             b'copyrev': b'b' * 40,
       
   773         }
       
   774         stored1 = b''.join([
       
   775             b'\x01\ncopy: source0\n',
       
   776             b'copyrev: %s\n' % (b'b' * 40),
       
   777             b'\x01\n\x01\nbar',
       
   778         ])
       
   779 
       
   780         f = self._makefilefn()
       
   781         with self._maketransactionfn() as tr:
       
   782             node0 = f.add(fulltext0, {}, tr, 0, nullid, nullid)
       
   783             node1 = f.add(fulltext1, meta1, tr, 1, nullid, nullid)
       
   784 
       
   785         self.assertEqual(f.rawsize(0), len(stored0))
       
   786         self.assertEqual(f.rawsize(1), len(stored1))
       
   787 
       
   788         # TODO this is buggy.
       
   789         self.assertEqual(f.size(0), len(fulltext0) + 4)
       
   790 
       
   791         self.assertEqual(f.size(1), len(fulltext1))
       
   792 
       
   793         self.assertEqual(f.revision(node0), stored0)
       
   794         self.assertEqual(f.revision(node0, raw=True), stored0)
       
   795 
       
   796         self.assertEqual(f.revision(node1), stored1)
       
   797         self.assertEqual(f.revision(node1, raw=True), stored1)
       
   798 
       
   799         self.assertEqual(f.read(node0), fulltext0)
       
   800         self.assertEqual(f.read(node1), fulltext1)
       
   801 
       
   802         self.assertFalse(f.cmp(node0, fulltext0))
       
   803         self.assertTrue(f.cmp(node0, stored0))
       
   804 
       
   805         self.assertFalse(f.cmp(node1, fulltext1))
       
   806         self.assertTrue(f.cmp(node1, stored0))
       
   807 
       
   808     def testcensored(self):
       
   809         f = self._makefilefn()
       
   810 
       
   811         stored1 = revlog.packmeta({
       
   812             b'censored': b'tombstone',
       
   813         }, b'')
       
   814 
       
   815         # TODO tests are incomplete because we need the node to be
       
   816         # different due to presence of censor metadata. But we can't
       
   817         # do this with addrevision().
       
   818         with self._maketransactionfn() as tr:
       
   819             node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
       
   820             f.addrevision(stored1, tr, 1, node0, nullid,
       
   821                           flags=revlog.REVIDX_ISCENSORED)
       
   822 
       
   823         self.assertEqual(f.flags(1), revlog.REVIDX_ISCENSORED)
       
   824         self.assertTrue(f.iscensored(1))
       
   825 
       
   826         self.assertEqual(f.revision(1), stored1)
       
   827         self.assertEqual(f.revision(1, raw=True), stored1)
       
   828 
       
   829         self.assertEqual(f.read(1), b'')
       
   830 
       
   831 class ifilemutationtests(basetestcase):
       
   832     """Generic tests for the ifilemutation interface.
       
   833 
       
   834     All file storage backends that support writing should conform to this
       
   835     interface.
       
   836 
       
   837     Use ``makeifilemutationtests()`` to create an instance of this type.
       
   838     """
       
   839     def testaddnoop(self):
       
   840         f = self._makefilefn()
       
   841         with self._maketransactionfn() as tr:
       
   842             node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
       
   843             node1 = f.add(b'foo', None, tr, 0, nullid, nullid)
       
   844             # Varying by linkrev shouldn't impact hash.
       
   845             node2 = f.add(b'foo', None, tr, 1, nullid, nullid)
       
   846 
       
   847         self.assertEqual(node1, node0)
       
   848         self.assertEqual(node2, node0)
       
   849         self.assertEqual(len(f), 1)
       
   850 
       
   851     def testaddrevisionbadnode(self):
       
   852         f = self._makefilefn()
       
   853         with self._maketransactionfn() as tr:
       
   854             # Adding a revision with bad node value fails.
       
   855             with self.assertRaises(error.RevlogError):
       
   856                 f.addrevision(b'foo', tr, 0, nullid, nullid, node=b'\x01' * 20)
       
   857 
       
   858     def testaddrevisionunknownflag(self):
       
   859         f = self._makefilefn()
       
   860         with self._maketransactionfn() as tr:
       
   861             for i in range(15, 0, -1):
       
   862                 if (1 << i) & ~revlog.REVIDX_KNOWN_FLAGS:
       
   863                     flags = 1 << i
       
   864                     break
       
   865 
       
   866             with self.assertRaises(error.RevlogError):
       
   867                 f.addrevision(b'foo', tr, 0, nullid, nullid, flags=flags)
       
   868 
       
   869     def testaddgroupsimple(self):
       
   870         f = self._makefilefn()
       
   871 
       
   872         callbackargs = []
       
   873         def cb(*args, **kwargs):
       
   874             callbackargs.append((args, kwargs))
       
   875 
       
   876         def linkmapper(node):
       
   877             return 0
       
   878 
       
   879         with self._maketransactionfn() as tr:
       
   880             nodes = f.addgroup([], None, tr, addrevisioncb=cb)
       
   881 
       
   882         self.assertEqual(nodes, [])
       
   883         self.assertEqual(callbackargs, [])
       
   884         self.assertEqual(len(f), 0)
       
   885 
       
   886         fulltext0 = b'foo'
       
   887         delta0 = mdiff.trivialdiffheader(len(fulltext0)) + fulltext0
       
   888 
       
   889         deltas = [
       
   890             (b'\x01' * 20, nullid, nullid, nullid, nullid, delta0, 0),
       
   891         ]
       
   892 
       
   893         with self._maketransactionfn() as tr:
       
   894             with self.assertRaises(error.RevlogError):
       
   895                 f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
       
   896 
       
   897             node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
       
   898 
       
   899         f = self._makefilefn()
       
   900 
       
   901         deltas = [
       
   902             (node0, nullid, nullid, nullid, nullid, delta0, 0),
       
   903         ]
       
   904 
       
   905         with self._maketransactionfn() as tr:
       
   906             nodes = f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
       
   907 
       
   908         self.assertEqual(nodes, [
       
   909             b'\x49\xd8\xcb\xb1\x5c\xe2\x57\x92\x04\x47'
       
   910             b'\x00\x6b\x46\x97\x8b\x7a\xf9\x80\xa9\x79'])
       
   911 
       
   912         self.assertEqual(len(callbackargs), 1)
       
   913         self.assertEqual(callbackargs[0][0][1], nodes[0])
       
   914 
       
   915         self.assertEqual(list(f.revs()), [0])
       
   916         self.assertEqual(f.rev(nodes[0]), 0)
       
   917         self.assertEqual(f.node(0), nodes[0])
       
   918 
       
   919     def testaddgroupmultiple(self):
       
   920         f = self._makefilefn()
       
   921 
       
   922         fulltexts = [
       
   923             b'foo',
       
   924             b'bar',
       
   925             b'x' * 1024,
       
   926         ]
       
   927 
       
   928         nodes = []
       
   929         with self._maketransactionfn() as tr:
       
   930             for fulltext in fulltexts:
       
   931                 nodes.append(f.add(fulltext, None, tr, 0, nullid, nullid))
       
   932 
       
   933         f = self._makefilefn()
       
   934         deltas = []
       
   935         for i, fulltext in enumerate(fulltexts):
       
   936             delta = mdiff.trivialdiffheader(len(fulltext)) + fulltext
       
   937 
       
   938             deltas.append((nodes[i], nullid, nullid, nullid, nullid, delta, 0))
       
   939 
       
   940         with self._maketransactionfn() as tr:
       
   941             self.assertEqual(f.addgroup(deltas, lambda x: 0, tr), nodes)
       
   942 
       
   943         self.assertEqual(len(f), len(deltas))
       
   944         self.assertEqual(list(f.revs()), [0, 1, 2])
       
   945         self.assertEqual(f.rev(nodes[0]), 0)
       
   946         self.assertEqual(f.rev(nodes[1]), 1)
       
   947         self.assertEqual(f.rev(nodes[2]), 2)
       
   948         self.assertEqual(f.node(0), nodes[0])
       
   949         self.assertEqual(f.node(1), nodes[1])
       
   950         self.assertEqual(f.node(2), nodes[2])
       
   951 
       
   952 def makeifileindextests(makefilefn, maketransactionfn):
       
   953     """Create a unittest.TestCase class suitable for testing file storage.
       
   954 
       
   955     ``makefilefn`` is a callable which receives the test case as an
       
   956     argument and returns an object implementing the ``ifilestorage`` interface.
       
   957 
       
   958     ``maketransactionfn`` is a callable which receives the test case as an
       
   959     argument and returns a transaction object.
       
   960 
       
   961     Returns a type that is a ``unittest.TestCase`` that can be used for
       
   962     testing the object implementing the file storage interface. Simply
       
   963     assign the returned value to a module-level attribute and a test loader
       
   964     should find and run it automatically.
       
   965     """
       
   966     d = {
       
   967         r'_makefilefn': makefilefn,
       
   968         r'_maketransactionfn': maketransactionfn,
       
   969     }
       
   970     return type(r'ifileindextests', (ifileindextests,), d)
       
   971 
       
   972 def makeifiledatatests(makefilefn, maketransactionfn):
       
   973     d = {
       
   974         r'_makefilefn': makefilefn,
       
   975         r'_maketransactionfn': maketransactionfn,
       
   976     }
       
   977     return type(r'ifiledatatests', (ifiledatatests,), d)
       
   978 
       
   979 def makeifilemutationtests(makefilefn, maketransactionfn):
       
   980     d = {
       
   981         r'_makefilefn': makefilefn,
       
   982         r'_maketransactionfn': maketransactionfn,
       
   983     }
       
   984     return type(r'ifilemutationtests', (ifilemutationtests,), d)