/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

mergeĀ fromĀ dirstate

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
    """Helper functions for creating DirState objects with various content."""
56
56
 
57
57
    def create_empty_dirstate(self):
 
58
        """Return a locked but empty dirstate"""
58
59
        state = dirstate.DirState.initialize('dirstate')
59
60
        return state
60
61
 
61
62
    def create_dirstate_with_root(self):
62
 
        state = self.create_empty_dirstate()
 
63
        """Return a write-locked state with a single root entry."""
63
64
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
64
65
        root_entry_direntry = ('', '', 'a-root-value'), [
65
 
            ('directory', '', 0, False, packed_stat),
 
66
            ('d', '', 0, False, packed_stat),
66
67
            ]
67
68
        dirblocks = []
68
69
        dirblocks.append(('', [root_entry_direntry]))
69
70
        dirblocks.append(('', []))
70
 
        state._set_data([], dirblocks)
 
71
        state = self.create_empty_dirstate()
 
72
        try:
 
73
            state._set_data([], dirblocks)
 
74
        except:
 
75
            state.unlock()
 
76
            raise
71
77
        return state
72
78
 
73
79
    def create_dirstate_with_root_and_subdir(self):
74
 
        state = self.create_dirstate_with_root()
 
80
        """Return a locked DirState with a root and a subdir"""
75
81
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
76
 
        dirblocks = list(state._dirblocks)
77
82
        subdir_entry = ('', 'subdir', 'subdir-id'), [
78
 
            ('directory', '', 0, False, packed_stat),
 
83
            ('d', '', 0, False, packed_stat),
79
84
            ]
80
 
        dirblocks[1][1].append(subdir_entry)
81
 
        state._set_data([], dirblocks)
 
85
        state = self.create_dirstate_with_root()
 
86
        try:
 
87
            dirblocks = list(state._dirblocks)
 
88
            dirblocks[1][1].append(subdir_entry)
 
89
            state._set_data([], dirblocks)
 
90
        except:
 
91
            state.unlock()
 
92
            raise
82
93
        return state
83
94
 
84
95
    def create_complex_dirstate(self):
96
107
 
97
108
        # Notice that a/e is an empty directory.
98
109
        """
99
 
        state = dirstate.DirState.initialize('dirstate')
100
110
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
101
111
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
102
112
        root_entry = ('', '', 'a-root-value'), [
103
 
            ('directory', '', 0, False, packed_stat),
 
113
            ('d', '', 0, False, packed_stat),
104
114
            ]
105
115
        a_entry = ('', 'a', 'a-dir'), [
106
 
            ('directory', '', 0, False, packed_stat),
 
116
            ('d', '', 0, False, packed_stat),
107
117
            ]
108
118
        b_entry = ('', 'b', 'b-dir'), [
109
 
            ('directory', '', 0, False, packed_stat),
 
119
            ('d', '', 0, False, packed_stat),
110
120
            ]
111
121
        c_entry = ('', 'c', 'c-file'), [
112
 
            ('file', null_sha, 10, False, packed_stat),
 
122
            ('f', null_sha, 10, False, packed_stat),
113
123
            ]
114
124
        d_entry = ('', 'd', 'd-file'), [
115
 
            ('file', null_sha, 20, False, packed_stat),
 
125
            ('f', null_sha, 20, False, packed_stat),
116
126
            ]
117
127
        e_entry = ('a', 'e', 'e-dir'), [
118
 
            ('directory', '', 0, False, packed_stat),
 
128
            ('d', '', 0, False, packed_stat),
119
129
            ]
120
130
        f_entry = ('a', 'f', 'f-file'), [
121
 
            ('file', null_sha, 30, False, packed_stat),
 
131
            ('f', null_sha, 30, False, packed_stat),
122
132
            ]
123
133
        g_entry = ('b', 'g', 'g-file'), [
124
 
            ('file', null_sha, 30, False, packed_stat),
 
134
            ('f', null_sha, 30, False, packed_stat),
125
135
            ]
126
136
        h_entry = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file'), [
127
 
            ('file', null_sha, 40, False, packed_stat),
 
137
            ('f', null_sha, 40, False, packed_stat),
128
138
            ]
129
139
        dirblocks = []
130
140
        dirblocks.append(('', [root_entry]))
131
141
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
132
142
        dirblocks.append(('a', [e_entry, f_entry]))
133
143
        dirblocks.append(('b', [g_entry, h_entry]))
134
 
        state._set_data([], dirblocks)
 
144
        state = dirstate.DirState.initialize('dirstate')
 
145
        try:
 
146
            state._set_data([], dirblocks)
 
147
        except:
 
148
            state.unlock()
 
149
            raise
135
150
        return state
136
151
 
137
152
    def check_state_with_reopen(self, expected_result, state):
138
153
        """Check that state has current state expected_result.
139
 
        
 
154
 
140
155
        This will check the current state, open the file anew and check it
141
156
        again.
 
157
        This function expects the current state to be locked for writing, and
 
158
        will unlock it before re-opening.
 
159
        This is required because we can't open a lock_read() while something
 
160
        else has a lock_write().
 
161
            write => mutually exclusive lock
 
162
            read => shared lock
142
163
        """
143
 
        self.assertEqual(expected_result[0],  state.get_parent_ids())
144
 
        # there should be no ghosts in this tree.
145
 
        self.assertEqual([], state.get_ghosts())
146
 
        # there should be one fileid in this tree - the root of the tree.
147
 
        self.assertEqual(expected_result[1], list(state._iter_entries()))
148
 
        state.save()
 
164
        # The state should already be write locked, since we just had to do
 
165
        # some operation to get here.
 
166
        assert state._lock_token is not None
 
167
        try:
 
168
            self.assertEqual(expected_result[0],  state.get_parent_ids())
 
169
            # there should be no ghosts in this tree.
 
170
            self.assertEqual([], state.get_ghosts())
 
171
            # there should be one fileid in this tree - the root of the tree.
 
172
            self.assertEqual(expected_result[1], list(state._iter_entries()))
 
173
            state.save()
 
174
        finally:
 
175
            state.unlock()
 
176
        del state # Callers should unlock
149
177
        state = dirstate.DirState.on_file('dirstate')
150
 
        self.assertEqual(expected_result[1], list(state._iter_entries()))
 
178
        state.lock_read()
 
179
        try:
 
180
            self.assertEqual(expected_result[1], list(state._iter_entries()))
 
181
        finally:
 
182
            state.unlock()
151
183
 
152
184
 
153
185
class TestTreeToDirState(TestCaseWithDirState):
156
188
        """We should be able to create a dirstate for an empty tree."""
157
189
        # There are no files on disk and no parents
158
190
        tree = self.make_branch_and_tree('tree')
159
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
160
191
        expected_result = ([], [
161
192
            (('', '', tree.path2id('')), # common details
162
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
193
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
163
194
             ])])
 
195
        state = dirstate.DirState.from_tree(tree, 'dirstate')
164
196
        self.check_state_with_reopen(expected_result, state)
165
197
 
166
198
    def test_1_parents_empty_to_dirstate(self):
167
199
        # create a parent by doing a commit
168
200
        tree = self.make_branch_and_tree('tree')
169
201
        rev_id = tree.commit('first post').encode('utf8')
170
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
171
202
        root_stat_pack = dirstate.pack_stat(os.stat(tree.basedir))
172
203
        expected_result = ([rev_id], [
173
204
            (('', '', tree.path2id('')), # common details
174
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
175
 
              ('directory', '', 0, False, rev_id), # first parent details
 
205
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
206
              ('d', '', 0, False, rev_id), # first parent details
176
207
             ])])
 
208
        state = dirstate.DirState.from_tree(tree, 'dirstate')
177
209
        self.check_state_with_reopen(expected_result, state)
178
210
 
179
211
    def test_2_parents_empty_to_dirstate(self):
183
215
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
184
216
        rev_id2 = tree2.commit('second post', allow_pointless=True)
185
217
        tree.merge_from_branch(tree2.branch)
186
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
187
218
        expected_result = ([rev_id, rev_id2], [
188
219
            (('', '', tree.path2id('')), # common details
189
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
190
 
              ('directory', '', 0, False, rev_id), # first parent details
191
 
              ('directory', '', 0, False, rev_id2), # second parent details
 
220
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
221
              ('d', '', 0, False, rev_id), # first parent details
 
222
              ('d', '', 0, False, rev_id2), # second parent details
192
223
             ])])
 
224
        state = dirstate.DirState.from_tree(tree, 'dirstate')
193
225
        self.check_state_with_reopen(expected_result, state)
194
 
        
 
226
 
195
227
    def test_empty_unknowns_are_ignored_to_dirstate(self):
196
228
        """We should be able to create a dirstate for an empty tree."""
197
229
        # There are no files on disk and no parents
198
230
        tree = self.make_branch_and_tree('tree')
199
231
        self.build_tree(['tree/unknown'])
200
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
201
232
        expected_result = ([], [
202
233
            (('', '', tree.path2id('')), # common details
203
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
234
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
204
235
             ])])
 
236
        state = dirstate.DirState.from_tree(tree, 'dirstate')
205
237
        self.check_state_with_reopen(expected_result, state)
206
 
        
 
238
 
207
239
    def get_tree_with_a_file(self):
208
240
        tree = self.make_branch_and_tree('tree')
209
241
        self.build_tree(['tree/a file'])
214
246
        """We should be able to create a dirstate for an empty tree."""
215
247
        # There are files on disk and no parents
216
248
        tree = self.get_tree_with_a_file()
217
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
218
249
        expected_result = ([], [
219
250
            (('', '', tree.path2id('')), # common details
220
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
251
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
221
252
             ]),
222
253
            (('', 'a file', 'a file id'), # common
223
 
             [('file', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
254
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
224
255
             ]),
225
256
            ])
 
257
        state = dirstate.DirState.from_tree(tree, 'dirstate')
226
258
        self.check_state_with_reopen(expected_result, state)
227
259
 
228
260
    def test_1_parents_not_empty_to_dirstate(self):
232
264
        # change the current content to be different this will alter stat, sha
233
265
        # and length:
234
266
        self.build_tree_contents([('tree/a file', 'new content\n')])
235
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
236
267
        expected_result = ([rev_id], [
237
268
            (('', '', tree.path2id('')), # common details
238
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
239
 
              ('directory', '', 0, False, rev_id), # first parent details
 
269
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
270
              ('d', '', 0, False, rev_id), # first parent details
240
271
             ]),
241
272
            (('', 'a file', 'a file id'), # common
242
 
             [('file', '', 0, False, dirstate.DirState.NULLSTAT), # current
243
 
              ('file', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False, rev_id), # first parent
 
273
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
274
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False, rev_id), # first parent
244
275
             ]),
245
276
            ])
 
277
        state = dirstate.DirState.from_tree(tree, 'dirstate')
246
278
        self.check_state_with_reopen(expected_result, state)
247
279
 
248
280
    def test_2_parents_not_empty_to_dirstate(self):
258
290
        # change the current content to be different this will alter stat, sha
259
291
        # and length again, giving us three distinct values:
260
292
        self.build_tree_contents([('tree/a file', 'new content\n')])
261
 
        state = dirstate.DirState.from_tree(tree, 'dirstate')
262
293
        expected_result = ([rev_id, rev_id2], [
263
294
            (('', '', tree.path2id('')), # common details
264
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
265
 
              ('directory', '', 0, False, rev_id), # first parent details
266
 
              ('directory', '', 0, False, rev_id2), # second parent details
 
295
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
296
              ('d', '', 0, False, rev_id), # first parent details
 
297
              ('d', '', 0, False, rev_id2), # second parent details
267
298
             ]),
268
299
            (('', 'a file', 'a file id'), # common
269
 
             [('file', '', 0, False, dirstate.DirState.NULLSTAT), # current
270
 
              ('file', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False, rev_id), # first parent
271
 
              ('file', '314d796174c9412647c3ce07dfb5d36a94e72958', 14, False, rev_id2), # second parent
 
300
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
301
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False, rev_id), # first parent
 
302
              ('f', '314d796174c9412647c3ce07dfb5d36a94e72958', 14, False, rev_id2), # second parent
272
303
             ]),
273
304
            ])
 
305
        state = dirstate.DirState.from_tree(tree, 'dirstate')
274
306
        self.check_state_with_reopen(expected_result, state)
275
307
 
276
308
 
282
314
        # we want to be able to get the lines of the dirstate that we will
283
315
        # write to disk.
284
316
        lines = state.get_lines()
 
317
        state.unlock()
285
318
        self.build_tree_contents([('dirstate', ''.join(lines))])
286
319
        # get a state object
287
 
        state = dirstate.DirState.on_file('dirstate')
288
320
        # no parents, default tree content
289
321
        expected_result = ([], [
290
322
            (('', '', tree.path2id('')), # common details
291
323
             # current tree details, but new from_tree skips statting, it
292
324
             # uses set_state_from_inventory, and thus depends on the
293
325
             # inventory state.
294
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT),
 
326
             [('d', '', 0, False, dirstate.DirState.NULLSTAT),
295
327
             ])
296
328
            ])
 
329
        state = dirstate.DirState.on_file('dirstate')
 
330
        state.lock_write() # check_state_with_reopen will save() and unlock it
297
331
        self.check_state_with_reopen(expected_result, state)
298
332
 
299
333
    def test_can_save_clean_on_file(self):
300
334
        tree = self.make_branch_and_tree('tree')
301
335
        state = dirstate.DirState.from_tree(tree, 'dirstate')
302
 
        # doing a save should work here as there have been no changes.
303
 
        state.save()
304
 
        # TODO: stat it and check it hasn't changed; may require waiting for
305
 
        # the state accuracy window.
 
336
        try:
 
337
            # doing a save should work here as there have been no changes.
 
338
            state.save()
 
339
            # TODO: stat it and check it hasn't changed; may require waiting for
 
340
            # the state accuracy window.
 
341
        finally:
 
342
            state.unlock()
306
343
 
307
344
 
308
345
class TestDirStateInitialize(TestCaseWithDirState):
309
346
 
310
347
    def test_initialize(self):
311
 
        state = dirstate.DirState.initialize('dirstate')
312
 
        self.assertIsInstance(state, dirstate.DirState)
313
 
        lines = state.get_lines()
314
 
        self.assertFileEqual(''.join(state.get_lines()),
315
 
            'dirstate')
316
348
        expected_result = ([], [
317
349
            (('', '', 'TREE_ROOT'), # common details
318
 
             [('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
350
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
319
351
             ])
320
352
            ])
321
 
        self.check_state_with_reopen(expected_result, state)
 
353
        state = dirstate.DirState.initialize('dirstate')
 
354
        try:
 
355
            self.assertIsInstance(state, dirstate.DirState)
 
356
            lines = state.get_lines()
 
357
            self.assertFileEqual(''.join(state.get_lines()),
 
358
                'dirstate')
 
359
            self.check_state_with_reopen(expected_result, state)
 
360
        except:
 
361
            state.unlock()
 
362
            raise
322
363
 
323
364
 
324
365
class TestDirStateManipulations(TestCaseWithDirState):
325
366
 
326
367
    def test_set_state_from_inventory_no_content_no_parents(self):
327
368
        # setting the current inventory is a slow but important api to support.
328
 
        state = dirstate.DirState.initialize('dirstate')
329
369
        tree1 = self.make_branch_and_memory_tree('tree1')
330
370
        tree1.lock_write()
331
 
        tree1.add('')
332
 
        revid1 = tree1.commit('foo').encode('utf8')
333
 
        root_id = tree1.inventory.root.file_id
334
 
        state.set_state_from_inventory(tree1.inventory)
335
 
        tree1.unlock()
336
 
        self.assertEqual(DirState.IN_MEMORY_UNMODIFIED, state._header_state)
337
 
        self.assertEqual(DirState.IN_MEMORY_MODIFIED, state._dirblock_state)
 
371
        try:
 
372
            tree1.add('')
 
373
            revid1 = tree1.commit('foo').encode('utf8')
 
374
            root_id = tree1.inventory.root.file_id
 
375
            inv = tree1.inventory
 
376
        finally:
 
377
            tree1.unlock()
338
378
        expected_result = [], [
339
379
            (('', '', root_id), [
340
 
             ('directory', '', 0, False, DirState.NULLSTAT)])]
341
 
        self.check_state_with_reopen(expected_result, state)
 
380
             ('d', '', 0, False, DirState.NULLSTAT)])]
 
381
        state = dirstate.DirState.initialize('dirstate')
 
382
        try:
 
383
            state.set_state_from_inventory(inv)
 
384
            self.assertEqual(DirState.IN_MEMORY_UNMODIFIED, state._header_state)
 
385
            self.assertEqual(DirState.IN_MEMORY_MODIFIED, state._dirblock_state)
 
386
        except:
 
387
            state.unlock()
 
388
            raise
 
389
        else:
 
390
            # This will unlock it
 
391
            self.check_state_with_reopen(expected_result, state)
342
392
 
343
393
    def test_set_path_id_no_parents(self):
344
394
        """The id of a path can be changed trivally with no parents."""
345
395
        state = dirstate.DirState.initialize('dirstate')
346
 
        # check precondition to be sure the state does change appropriately.
347
 
        self.assertEqual(
348
 
            [(('', '', 'TREE_ROOT'), [('directory', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])],
349
 
            list(state._iter_entries()))
350
 
        state.set_path_id('', 'foobarbaz')
351
 
        expected_rows = [
352
 
            (('', '', 'foobarbaz'), [('directory', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])]
353
 
        self.assertEqual(expected_rows, list(state._iter_entries()))
354
 
        # should work across save too
355
 
        state.save()
 
396
        try:
 
397
            # check precondition to be sure the state does change appropriately.
 
398
            self.assertEqual(
 
399
                [(('', '', 'TREE_ROOT'), [('d', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])],
 
400
                list(state._iter_entries()))
 
401
            state.set_path_id('', 'foobarbaz')
 
402
            expected_rows = [
 
403
                (('', '', 'foobarbaz'), [('d', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])]
 
404
            self.assertEqual(expected_rows, list(state._iter_entries()))
 
405
            # should work across save too
 
406
            state.save()
 
407
        finally:
 
408
            state.unlock()
356
409
        state = dirstate.DirState.on_file('dirstate')
357
 
        self.assertEqual(expected_rows, list(state._iter_entries()))
 
410
        state.lock_read()
 
411
        try:
 
412
            self.assertEqual(expected_rows, list(state._iter_entries()))
 
413
        finally:
 
414
            state.unlock()
358
415
 
359
416
    def test_set_parent_trees_no_content(self):
360
417
        # set_parent_trees is a slow but important api to support.
361
 
        state = dirstate.DirState.initialize('dirstate')
362
418
        tree1 = self.make_branch_and_memory_tree('tree1')
363
419
        tree1.lock_write()
364
 
        tree1.add('')
365
 
        revid1 = tree1.commit('foo')
366
 
        tree1.unlock()
 
420
        try:
 
421
            tree1.add('')
 
422
            revid1 = tree1.commit('foo')
 
423
        finally:
 
424
            tree1.unlock()
367
425
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
368
426
        tree2 = MemoryTree.create_on_branch(branch2)
369
427
        tree2.lock_write()
370
 
        revid2 = tree2.commit('foo')
371
 
        root_id = tree2.inventory.root.file_id
372
 
        state.set_path_id('', root_id)
373
 
        tree2.unlock()
374
 
        state.set_parent_trees(
375
 
            ((revid1, tree1.branch.repository.revision_tree(revid1)),
376
 
             (revid2, tree2.branch.repository.revision_tree(revid2)),
377
 
             ('ghost-rev', None)),
378
 
            ['ghost-rev'])
379
 
        # check we can reopen and use the dirstate after setting parent trees.
380
 
        state.save()
 
428
        try:
 
429
            revid2 = tree2.commit('foo')
 
430
            root_id = tree2.inventory.root.file_id
 
431
        finally:
 
432
            tree2.unlock()
 
433
        state = dirstate.DirState.initialize('dirstate')
 
434
        try:
 
435
            state.set_path_id('', root_id)
 
436
            state.set_parent_trees(
 
437
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
 
438
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
 
439
                 ('ghost-rev', None)),
 
440
                ['ghost-rev'])
 
441
            # check we can reopen and use the dirstate after setting parent trees.
 
442
            state.save()
 
443
        finally:
 
444
            state.unlock()
381
445
        state = dirstate.DirState.on_file('dirstate')
382
 
        self.assertEqual([revid1, revid2, 'ghost-rev'],  state.get_parent_ids())
383
 
        # iterating the entire state ensures that the state is parsable.
384
 
        list(state._iter_entries())
385
 
        # be sure that it sets not appends - change it
386
 
        state.set_parent_trees(
387
 
            ((revid1, tree1.branch.repository.revision_tree(revid1)),
388
 
             ('ghost-rev', None)),
389
 
            ['ghost-rev'])
390
 
        # and now put it back.
391
 
        state.set_parent_trees(
392
 
            ((revid1, tree1.branch.repository.revision_tree(revid1)),
393
 
             (revid2, tree2.branch.repository.revision_tree(revid2)),
394
 
             ('ghost-rev', tree2.branch.repository.revision_tree(None))),
395
 
            ['ghost-rev'])
396
 
        self.assertEqual([revid1, revid2, 'ghost-rev'],  state.get_parent_ids())
397
 
        # the ghost should be recorded as such by set_parent_trees.
398
 
        self.assertEqual(['ghost-rev'], state.get_ghosts())
399
 
        self.assertEqual(
400
 
            [(('', '', root_id), [
401
 
              ('directory', '', 0, False, DirState.NULLSTAT),
402
 
              ('directory', '', 0, False, revid1),
403
 
              ('directory', '', 0, False, revid2)
404
 
              ])],
405
 
            list(state._iter_entries()))
 
446
        state.lock_write()
 
447
        try:
 
448
            self.assertEqual([revid1, revid2, 'ghost-rev'],
 
449
                             state.get_parent_ids())
 
450
            # iterating the entire state ensures that the state is parsable.
 
451
            list(state._iter_entries())
 
452
            # be sure that it sets not appends - change it
 
453
            state.set_parent_trees(
 
454
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
 
455
                 ('ghost-rev', None)),
 
456
                ['ghost-rev'])
 
457
            # and now put it back.
 
458
            state.set_parent_trees(
 
459
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
 
460
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
 
461
                 ('ghost-rev', tree2.branch.repository.revision_tree(None))),
 
462
                ['ghost-rev'])
 
463
            self.assertEqual([revid1, revid2, 'ghost-rev'],
 
464
                             state.get_parent_ids())
 
465
            # the ghost should be recorded as such by set_parent_trees.
 
466
            self.assertEqual(['ghost-rev'], state.get_ghosts())
 
467
            self.assertEqual(
 
468
                [(('', '', root_id), [
 
469
                  ('d', '', 0, False, DirState.NULLSTAT),
 
470
                  ('d', '', 0, False, revid1),
 
471
                  ('d', '', 0, False, revid2)
 
472
                  ])],
 
473
                list(state._iter_entries()))
 
474
        finally:
 
475
            state.unlock()
406
476
 
407
477
    def test_set_parent_trees_file_missing_from_tree(self):
408
478
        # Adding a parent tree may reference files not in the current state.
409
479
        # they should get listed just once by id, even if they are in two  
410
480
        # separate trees.
411
481
        # set_parent_trees is a slow but important api to support.
412
 
        state = dirstate.DirState.initialize('dirstate')
413
482
        tree1 = self.make_branch_and_memory_tree('tree1')
414
483
        tree1.lock_write()
415
 
        tree1.add('')
416
 
        tree1.add(['a file'], ['file-id'], ['file'])
417
 
        tree1.put_file_bytes_non_atomic('file-id', 'file-content')
418
 
        revid1 = tree1.commit('foo')
419
 
        tree1.unlock()
 
484
        try:
 
485
            tree1.add('')
 
486
            tree1.add(['a file'], ['file-id'], ['file'])
 
487
            tree1.put_file_bytes_non_atomic('file-id', 'file-content')
 
488
            revid1 = tree1.commit('foo')
 
489
        finally:
 
490
            tree1.unlock()
420
491
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
421
492
        tree2 = MemoryTree.create_on_branch(branch2)
422
493
        tree2.lock_write()
423
 
        tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
424
 
        revid2 = tree2.commit('foo')
425
 
        root_id = tree2.inventory.root.file_id
426
 
        state.set_path_id('', root_id)
427
 
        tree2.unlock()
428
 
        state.set_parent_trees(
429
 
            ((revid1, tree1.branch.repository.revision_tree(revid1)),
430
 
             (revid2, tree2.branch.repository.revision_tree(revid2)),
431
 
             ), [])
 
494
        try:
 
495
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
 
496
            revid2 = tree2.commit('foo')
 
497
            root_id = tree2.inventory.root.file_id
 
498
        finally:
 
499
            tree2.unlock()
432
500
        # check the layout in memory
433
501
        expected_result = [revid1.encode('utf8'), revid2.encode('utf8')], [
434
502
            (('', '', root_id), [
435
 
             ('directory', '', 0, False, DirState.NULLSTAT),
436
 
             ('directory', '', 0, False, revid1.encode('utf8')),
437
 
             ('directory', '', 0, False, revid2.encode('utf8'))]),
 
503
             ('d', '', 0, False, DirState.NULLSTAT),
 
504
             ('d', '', 0, False, revid1.encode('utf8')),
 
505
             ('d', '', 0, False, revid2.encode('utf8'))]),
438
506
            (('', 'a file', 'file-id'), [
439
 
             ('absent', '', 0, False, ''),
440
 
             ('file', '2439573625385400f2a669657a7db6ae7515d371', 12, False, revid1.encode('utf8')),
441
 
             ('file', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False, revid2.encode('utf8'))])
 
507
             ('a', '', 0, False, ''),
 
508
             ('f', '2439573625385400f2a669657a7db6ae7515d371', 12, False, revid1.encode('utf8')),
 
509
             ('f', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False, revid2.encode('utf8'))])
442
510
            ]
443
 
        self.check_state_with_reopen(expected_result, state)
 
511
        state = dirstate.DirState.initialize('dirstate')
 
512
        try:
 
513
            state.set_path_id('', root_id)
 
514
            state.set_parent_trees(
 
515
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
 
516
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
 
517
                 ), [])
 
518
        except:
 
519
            state.unlock()
 
520
            raise
 
521
        else:
 
522
            # check_state_with_reopen will unlock
 
523
            self.check_state_with_reopen(expected_result, state)
444
524
 
445
525
    ### add a path via _set_data - so we dont need delta work, just
446
526
    # raw data in, and ensure that it comes out via get_lines happily.
448
528
    def test_add_path_to_root_no_parents_all_data(self):
449
529
        # The most trivial addition of a path is when there are no parents and
450
530
        # its in the root and all data about the file is supplied
451
 
        state = dirstate.DirState.initialize('dirstate')
452
531
        self.build_tree(['a file'])
453
532
        stat = os.lstat('a file')
454
533
        # the 1*20 is the sha1 pretend value.
455
 
        state.add('a file', 'a file id', 'file', stat, '1'*20)
456
 
        # having added it, it should be in the output of iter_entries.
 
534
        state = dirstate.DirState.initialize('dirstate')
457
535
        expected_entries = [
458
536
            (('', '', 'TREE_ROOT'), [
459
 
             ('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
537
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
460
538
             ]),
461
539
            (('', 'a file', 'a file id'), [
462
 
             ('file', '1'*20, 19, False, dirstate.pack_stat(stat)), # current tree details
 
540
             ('f', '1'*20, 19, False, dirstate.pack_stat(stat)), # current tree details
463
541
             ]),
464
542
            ]
465
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
466
 
        # saving and reloading should not affect this.
467
 
        state.save()
 
543
        try:
 
544
            state.add('a file', 'a file id', 'file', stat, '1'*20)
 
545
            # having added it, it should be in the output of iter_entries.
 
546
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
547
            # saving and reloading should not affect this.
 
548
            state.save()
 
549
        finally:
 
550
            state.unlock()
468
551
        state = dirstate.DirState.on_file('dirstate')
469
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
552
        state.lock_read()
 
553
        try:
 
554
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
555
        finally:
 
556
            state.unlock()
470
557
 
471
558
    def test_add_path_to_unversioned_directory(self):
472
559
        """Adding a path to an unversioned directory should error.
473
 
        
474
 
        This is a duplicate of TestWorkingTree.test_add_in_unversioned, 
 
560
 
 
561
        This is a duplicate of TestWorkingTree.test_add_in_unversioned,
475
562
        once dirstate is stable and if it is merged with WorkingTree3, consider
476
563
        removing this copy of the test.
477
564
        """
478
 
        state = dirstate.DirState.initialize('dirstate')
479
565
        self.build_tree(['unversioned/', 'unversioned/a file'])
480
 
        self.assertRaises(errors.NotVersionedError, state.add,
481
 
            'unversioned/a file', 'a file id', 'file', None, None)
482
 
        
 
566
        state = dirstate.DirState.initialize('dirstate')
 
567
        try:
 
568
            self.assertRaises(errors.NotVersionedError, state.add,
 
569
                'unversioned/a file', 'a file id', 'file', None, None)
 
570
        finally:
 
571
            state.unlock()
 
572
 
483
573
    def test_add_directory_to_root_no_parents_all_data(self):
484
574
        # The most trivial addition of a dir is when there are no parents and
485
575
        # its in the root and all data about the file is supplied
486
 
        state = dirstate.DirState.initialize('dirstate')
487
576
        self.build_tree(['a dir/'])
488
577
        stat = os.lstat('a dir')
489
 
        state.add('a dir', 'a dir id', 'directory', stat, None)
490
 
        # having added it, it should be in the output of iter_entries.
491
578
        expected_entries = [
492
579
            (('', '', 'TREE_ROOT'), [
493
 
             ('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
580
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
494
581
             ]),
495
582
            (('', 'a dir', 'a dir id'), [
496
 
             ('directory', '', 0, False, dirstate.pack_stat(stat)), # current tree details
 
583
             ('d', '', 0, False, dirstate.pack_stat(stat)), # current tree details
497
584
             ]),
498
585
            ]
499
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
500
 
        # saving and reloading should not affect this.
501
 
        state.save()
 
586
        state = dirstate.DirState.initialize('dirstate')
 
587
        try:
 
588
            state.add('a dir', 'a dir id', 'directory', stat, None)
 
589
            # having added it, it should be in the output of iter_entries.
 
590
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
591
            # saving and reloading should not affect this.
 
592
            state.save()
 
593
        finally:
 
594
            state.unlock()
502
595
        state = dirstate.DirState.on_file('dirstate')
503
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
596
        state.lock_read()
 
597
        try:
 
598
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
599
        finally:
 
600
            state.unlock()
504
601
 
505
602
    def test_add_symlink_to_root_no_parents_all_data(self):
506
603
        # The most trivial addition of a symlink when there are no parents and
507
604
        # its in the root and all data about the file is supplied
508
 
        state = dirstate.DirState.initialize('dirstate')
509
605
        ## TODO: windows: dont fail this test. Also, how are symlinks meant to
510
606
        # be represented on windows.
511
607
        os.symlink('target', 'a link')
512
608
        stat = os.lstat('a link')
513
 
        state.add('a link', 'a link id', 'symlink', stat, 'target')
514
 
        # having added it, it should be in the output of iter_entries.
515
609
        expected_entries = [
516
610
            (('', '', 'TREE_ROOT'), [
517
 
             ('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
611
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
518
612
             ]),
519
613
            (('', 'a link', 'a link id'), [
520
 
             ('symlink', 'target', 6, False, dirstate.pack_stat(stat)), # current tree details
 
614
             ('l', 'target', 6, False, dirstate.pack_stat(stat)), # current tree details
521
615
             ]),
522
616
            ]
523
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
524
 
        # saving and reloading should not affect this.
525
 
        state.save()
 
617
        state = dirstate.DirState.initialize('dirstate')
 
618
        try:
 
619
            state.add('a link', 'a link id', 'symlink', stat, 'target')
 
620
            # having added it, it should be in the output of iter_entries.
 
621
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
622
            # saving and reloading should not affect this.
 
623
            state.save()
 
624
        finally:
 
625
            state.unlock()
526
626
        state = dirstate.DirState.on_file('dirstate')
527
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
627
        state.lock_read()
 
628
        try:
 
629
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
630
        finally:
 
631
            state.unlock()
528
632
 
529
633
    def test_add_directory_and_child_no_parents_all_data(self):
530
634
        # after adding a directory, we should be able to add children to it.
531
 
        state = dirstate.DirState.initialize('dirstate')
532
635
        self.build_tree(['a dir/', 'a dir/a file'])
533
 
        stat = os.lstat('a dir')
534
 
        state.add('a dir', 'a dir id', 'directory', stat, None)
 
636
        dirstat = os.lstat('a dir')
535
637
        filestat = os.lstat('a dir/a file')
536
 
        state.add('a dir/a file', 'a file id', 'file', filestat, '1'*20)
537
 
        # having added it, it should be in the output of iter_entries.
538
638
        expected_entries = [
539
639
            (('', '', 'TREE_ROOT'), [
540
 
             ('directory', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
 
640
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree details
541
641
             ]),
542
642
            (('', 'a dir', 'a dir id'), [
543
 
             ('directory', '', 0, False, dirstate.pack_stat(stat)), # current tree details
 
643
             ('d', '', 0, False, dirstate.pack_stat(dirstat)), # current tree details
544
644
             ]),
545
645
            (('a dir', 'a file', 'a file id'), [
546
 
             ('file', '1'*20, 25, False, dirstate.pack_stat(filestat)), # current tree details
 
646
             ('f', '1'*20, 25, False, dirstate.pack_stat(filestat)), # current tree details
547
647
             ]),
548
648
            ]
549
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
550
 
        # saving and reloading should not affect this.
551
 
        state.save()
 
649
        state = dirstate.DirState.initialize('dirstate')
 
650
        try:
 
651
            state.add('a dir', 'a dir id', 'directory', dirstat, None)
 
652
            state.add('a dir/a file', 'a file id', 'file', filestat, '1'*20)
 
653
            # added it, it should be in the output of iter_entries.
 
654
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
655
            # saving and reloading should not affect this.
 
656
            state.save()
 
657
        finally:
 
658
            state.unlock()
552
659
        state = dirstate.DirState.on_file('dirstate')
553
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
660
        state.lock_read()
 
661
        try:
 
662
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
663
        finally:
 
664
            state.unlock()
554
665
 
555
666
 
556
667
class TestGetLines(TestCaseWithDirState):
557
668
 
558
669
    def test_get_line_with_2_rows(self):
559
670
        state = self.create_dirstate_with_root_and_subdir()
560
 
        self.assertEqual(['#bazaar dirstate flat format 2\n',
561
 
            'adler32: -1327947603\n',
562
 
            'num_entries: 2\n',
563
 
            '0\x00\n\x00'
564
 
            '0\x00\n\x00'
565
 
            '\x00\x00a-root-value\x00'
566
 
            'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
567
 
            '\x00subdir\x00subdir-id\x00'
568
 
            'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'],
569
 
            state.get_lines())
 
671
        try:
 
672
            self.assertEqual(['#bazaar dirstate flat format 2\n',
 
673
                'adler32: -1327947603\n',
 
674
                'num_entries: 2\n',
 
675
                '0\x00\n\x00'
 
676
                '0\x00\n\x00'
 
677
                '\x00\x00a-root-value\x00'
 
678
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
 
679
                '\x00subdir\x00subdir-id\x00'
 
680
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'],
 
681
                state.get_lines())
 
682
        finally:
 
683
            state.unlock()
570
684
 
571
685
    def test_entry_to_line(self):
572
686
        state = self.create_dirstate_with_root()
573
 
        self.assertEqual(
574
 
            '\x00\x00a-root-value\x00d\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
575
 
            state._entry_to_line(state._dirblocks[0][1][0]))
 
687
        try:
 
688
            self.assertEqual(
 
689
                '\x00\x00a-root-value\x00d\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
 
690
                state._entry_to_line(state._dirblocks[0][1][0]))
 
691
        finally:
 
692
            state.unlock()
576
693
 
577
694
    def test_entry_to_line_with_parent(self):
578
 
        state = dirstate.DirState.initialize('dirstate')
579
695
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
580
696
        root_entry = ('', '', 'a-root-value'), [
581
 
            ('directory', '', 0, False, packed_stat), # current tree details
582
 
            ('absent', 'dirname/basename', 0, False, ''), # first: a pointer to the current location
 
697
            ('d', '', 0, False, packed_stat), # current tree details
 
698
            ('a', 'dirname/basename', 0, False, ''), # first: a pointer to the current location
583
699
            ]
584
 
        self.assertEqual(
585
 
            '\x00\x00a-root-value\x00'
586
 
            'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
587
 
            'a\x00dirname/basename\x000\x00n\x00',
588
 
            state._entry_to_line(root_entry))
 
700
        state = dirstate.DirState.initialize('dirstate')
 
701
        try:
 
702
            self.assertEqual(
 
703
                '\x00\x00a-root-value\x00'
 
704
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
 
705
                'a\x00dirname/basename\x000\x00n\x00',
 
706
                state._entry_to_line(root_entry))
 
707
        finally:
 
708
            state.unlock()
589
709
 
590
710
    def test_entry_to_line_with_two_parents_at_different_paths(self):
591
711
        # / in the tree, at / in one parent and /dirname/basename in the other.
592
 
        state = dirstate.DirState.initialize('dirstate')
593
712
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
594
713
        root_entry = ('', '', 'a-root-value'), [
595
 
            ('directory', '', 0, False, packed_stat), # current tree details
596
 
            ('directory', '', 0, False, 'rev_id'), # first parent details
597
 
            ('absent', 'dirname/basename', 0, False, ''), # second: a pointer to the current location
 
714
            ('d', '', 0, False, packed_stat), # current tree details
 
715
            ('d', '', 0, False, 'rev_id'), # first parent details
 
716
            ('a', 'dirname/basename', 0, False, ''), # second: a pointer to the current location
598
717
            ]
599
 
        self.assertEqual(
600
 
            '\x00\x00a-root-value\x00'
601
 
            'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
602
 
            'd\x00\x000\x00n\x00rev_id\x00'
603
 
            'a\x00dirname/basename\x000\x00n\x00',
604
 
            state._entry_to_line(root_entry))
 
718
        state = dirstate.DirState.initialize('dirstate')
 
719
        try:
 
720
            self.assertEqual(
 
721
                '\x00\x00a-root-value\x00'
 
722
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
 
723
                'd\x00\x000\x00n\x00rev_id\x00'
 
724
                'a\x00dirname/basename\x000\x00n\x00',
 
725
                state._entry_to_line(root_entry))
 
726
        finally:
 
727
            state.unlock()
605
728
 
606
729
    def test_iter_entries(self):
607
730
        # we should be able to iterate the dirstate entries from end to end
608
731
        # this is for get_lines to be easy to read.
609
 
        state = dirstate.DirState.initialize('dirstate')
610
732
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
611
733
        dirblocks = []
612
734
        root_entries = [(('', '', 'a-root-value'), [
613
 
            ('directory', '', 0, False, packed_stat), # current tree details
 
735
            ('d', '', 0, False, packed_stat), # current tree details
614
736
            ])]
615
737
        dirblocks.append(('', root_entries))
616
738
        # add two files in the root
617
739
        subdir_entry = ('', 'subdir', 'subdir-id'), [
618
 
            ('directory', '', 0, False, packed_stat), # current tree details
 
740
            ('d', '', 0, False, packed_stat), # current tree details
619
741
            ]
620
742
        afile_entry = ('', 'afile', 'afile-id'), [
621
 
            ('file', 'sha1value', 34, False, packed_stat), # current tree details
 
743
            ('f', 'sha1value', 34, False, packed_stat), # current tree details
622
744
            ]
623
745
        dirblocks.append(('', [subdir_entry, afile_entry]))
624
746
        # and one in subdir
625
747
        file_entry2 = ('subdir', '2file', '2file-id'), [
626
 
            ('file', 'sha1value', 23, False, packed_stat), # current tree details
 
748
            ('f', 'sha1value', 23, False, packed_stat), # current tree details
627
749
            ]
628
750
        dirblocks.append(('subdir', [file_entry2]))
629
 
        state._set_data([], dirblocks)
630
 
        expected_entries = [root_entries[0], subdir_entry, afile_entry, file_entry2]
631
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
751
        state = dirstate.DirState.initialize('dirstate')
 
752
        try:
 
753
            state._set_data([], dirblocks)
 
754
            expected_entries = [root_entries[0], subdir_entry, afile_entry, file_entry2]
 
755
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
756
        finally:
 
757
            state.unlock()
632
758
 
633
759
 
634
760
class TestGetBlockRowIndex(TestCaseWithDirState):
647
773
 
648
774
    def test_simple_structure(self):
649
775
        state = self.create_dirstate_with_root_and_subdir()
 
776
        self.addCleanup(state.unlock)
650
777
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
651
778
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
652
779
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
655
782
 
656
783
    def test_complex_structure_exists(self):
657
784
        state = self.create_complex_dirstate()
 
785
        self.addCleanup(state.unlock)
658
786
        # Make sure we can find everything that exists
659
787
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
660
788
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
668
796
 
669
797
    def test_complex_structure_missing(self):
670
798
        state = self.create_complex_dirstate()
 
799
        self.addCleanup(state.unlock)
671
800
        # Make sure things would be inserted in the right locations
672
801
        # '_' comes before 'a'
673
802
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
696
825
 
697
826
    def test_simple_structure(self):
698
827
        state = self.create_dirstate_with_root_and_subdir()
 
828
        self.addCleanup(state.unlock)
699
829
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
700
830
        self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
701
831
        self.assertEntryEqual(None, None, None, state, 'missing', 0)
704
834
 
705
835
    def test_complex_structure_exists(self):
706
836
        state = self.create_complex_dirstate()
 
837
        self.addCleanup(state.unlock)
707
838
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
708
839
        self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
709
840
        self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
716
847
 
717
848
    def test_complex_structure_missing(self):
718
849
        state = self.create_complex_dirstate()
 
850
        self.addCleanup(state.unlock)
719
851
        self.assertEntryEqual(None, None, None, state, '_', 0)
720
852
        self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
721
853
        self.assertEntryEqual(None, None, None, state, 'a/b', 0)
724
856
    def test_get_entry_uninitialized(self):
725
857
        """Calling get_entry will load data if it needs to"""
726
858
        state = self.create_dirstate_with_root()
727
 
        state.save()
 
859
        try:
 
860
            state.save()
 
861
        finally:
 
862
            state.unlock()
728
863
        del state
729
864
        state = dirstate.DirState.on_file('dirstate')
730
 
        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._header_state)
731
 
        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._dirblock_state)
732
 
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
 
865
        state.lock_read()
 
866
        try:
 
867
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._header_state)
 
868
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._dirblock_state)
 
869
            self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
 
870
        finally:
 
871
            state.unlock()