/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_osutils.py

  • Committer: Jelmer Vernooij
  • Date: 2009-05-28 16:04:39 UTC
  • mfrom: (4387 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4405.
  • Revision ID: jelmer@samba.org-20090528160439-4z0xlrk5nejobm7q
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
    tests,
32
32
    win32utils,
33
33
    )
34
 
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
35
 
from bzrlib.osutils import (
36
 
        is_inside_any,
37
 
        is_inside_or_parent_of_any,
38
 
        pathjoin,
39
 
        pumpfile,
40
 
        pump_string_file,
41
 
        canonical_relpath,
42
 
        )
43
34
from bzrlib.tests import (
44
 
        Feature,
45
 
        probe_unicode_in_user_encoding,
46
 
        StringIOWrapper,
47
 
        SymlinkFeature,
48
 
        CaseInsCasePresFilenameFeature,
49
 
        TestCase,
50
 
        TestCaseInTempDir,
51
 
        TestSkipped,
52
 
        )
53
 
from bzrlib.tests.file_utils import (
54
 
    FakeReadFile,
 
35
    file_utils,
 
36
    test__walkdirs_win32,
55
37
    )
56
 
from bzrlib.tests.test__walkdirs_win32 import Win32ReadDirFeature
57
 
 
58
 
 
59
 
class _UTF8DirReaderFeature(Feature):
 
38
 
 
39
 
 
40
class _UTF8DirReaderFeature(tests.Feature):
60
41
 
61
42
    def _probe(self):
62
43
        try:
72
53
UTF8DirReaderFeature = _UTF8DirReaderFeature()
73
54
 
74
55
 
75
 
class TestOSUtils(TestCaseInTempDir):
 
56
def _already_unicode(s):
 
57
    return s
 
58
 
 
59
 
 
60
def _fs_enc_to_unicode(s):
 
61
    return s.decode(osutils._fs_enc)
 
62
 
 
63
 
 
64
def _utf8_to_unicode(s):
 
65
    return s.decode('UTF-8')
 
66
 
 
67
 
 
68
def dir_reader_scenarios():
 
69
    # For each dir reader we define:
 
70
 
 
71
    # - native_to_unicode: a function converting the native_abspath as returned
 
72
    #   by DirReader.read_dir to its unicode representation
 
73
 
 
74
    # UnicodeDirReader is the fallback, it should be tested on all platforms.
 
75
    scenarios = [('unicode',
 
76
                  dict(_dir_reader_class=osutils.UnicodeDirReader,
 
77
                       _native_to_unicode=_already_unicode))]
 
78
    # Some DirReaders are platform specific and even there they may not be
 
79
    # available.
 
80
    if UTF8DirReaderFeature.available():
 
81
        from bzrlib import _readdir_pyx
 
82
        scenarios.append(('utf8',
 
83
                          dict(_dir_reader_class=_readdir_pyx.UTF8DirReader,
 
84
                               _native_to_unicode=_utf8_to_unicode)))
 
85
 
 
86
    if test__walkdirs_win32.Win32ReadDirFeature.available():
 
87
        try:
 
88
            from bzrlib import _walkdirs_win32
 
89
            # TODO: check on windows, it may be that we need to use/add
 
90
            # safe_unicode instead of _fs_enc_to_unicode
 
91
            scenarios.append(
 
92
                ('win32',
 
93
                 dict(_dir_reader_class=_walkdirs_win32.Win32ReadDir,
 
94
                      _native_to_unicode=_fs_enc_to_unicode)))
 
95
        except ImportError:
 
96
            pass
 
97
    return scenarios
 
98
 
 
99
 
 
100
def load_tests(basic_tests, module, loader):
 
101
    suite = loader.suiteClass()
 
102
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
 
103
        basic_tests, tests.condition_isinstance(TestDirReader))
 
104
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios(), suite)
 
105
    suite.addTest(remaining_tests)
 
106
    return suite
 
107
 
 
108
 
 
109
class TestContainsWhitespace(tests.TestCase):
76
110
 
77
111
    def test_contains_whitespace(self):
78
112
        self.failUnless(osutils.contains_whitespace(u' '))
88
122
        self.failIf(osutils.contains_whitespace(u'hellothere'))
89
123
        self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
90
124
 
 
125
 
 
126
class TestRename(tests.TestCaseInTempDir):
 
127
 
91
128
    def test_fancy_rename(self):
92
129
        # This should work everywhere
93
130
        def rename(a, b):
131
168
        shape = sorted(os.listdir('.'))
132
169
        self.assertEquals(['A', 'B'], shape)
133
170
 
 
171
 
 
172
class TestRandChars(tests.TestCase):
 
173
 
134
174
    def test_01_rand_chars_empty(self):
135
175
        result = osutils.rand_chars(0)
136
176
        self.assertEqual(result, '')
141
181
        self.assertEqual(type(result), str)
142
182
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
143
183
 
 
184
 
 
185
class TestIsInside(tests.TestCase):
 
186
 
144
187
    def test_is_inside(self):
145
188
        is_inside = osutils.is_inside
146
189
        self.assertTrue(is_inside('src', 'src/foo.c'))
151
194
        self.assertTrue(is_inside('', 'foo.c'))
152
195
 
153
196
    def test_is_inside_any(self):
154
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
197
        SRC_FOO_C = osutils.pathjoin('src', 'foo.c')
155
198
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
156
199
                         (['src'], SRC_FOO_C),
157
200
                         (['src'], 'src'),
158
201
                         ]:
159
 
            self.assert_(is_inside_any(dirs, fn))
 
202
            self.assert_(osutils.is_inside_any(dirs, fn))
160
203
        for dirs, fn in [(['src'], 'srccontrol'),
161
204
                         (['src'], 'srccontrol/foo')]:
162
 
            self.assertFalse(is_inside_any(dirs, fn))
 
205
            self.assertFalse(osutils.is_inside_any(dirs, fn))
163
206
 
164
207
    def test_is_inside_or_parent_of_any(self):
165
208
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
168
211
                         (['src/bar.c', 'bla/foo.c'], 'src'),
169
212
                         (['src'], 'src'),
170
213
                         ]:
171
 
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
 
214
            self.assert_(osutils.is_inside_or_parent_of_any(dirs, fn))
172
215
 
173
216
        for dirs, fn in [(['src'], 'srccontrol'),
174
217
                         (['srccontrol/foo.c'], 'src'),
175
218
                         (['src'], 'srccontrol/foo')]:
176
 
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
 
219
            self.assertFalse(osutils.is_inside_or_parent_of_any(dirs, fn))
 
220
 
 
221
 
 
222
class TestRmTree(tests.TestCaseInTempDir):
177
223
 
178
224
    def test_rmtree(self):
179
225
        # Check to remove tree with read-only files/dirs
193
239
        self.failIfExists('dir/file')
194
240
        self.failIfExists('dir')
195
241
 
 
242
 
 
243
class TestKind(tests.TestCaseInTempDir):
 
244
 
196
245
    def test_file_kind(self):
197
246
        self.build_tree(['file', 'dir/'])
198
247
        self.assertEquals('file', osutils.file_kind('file'))
228
277
                os.remove('socket')
229
278
 
230
279
    def test_kind_marker(self):
231
 
        self.assertEqual(osutils.kind_marker('file'), '')
232
 
        self.assertEqual(osutils.kind_marker('directory'), '/')
233
 
        self.assertEqual(osutils.kind_marker('symlink'), '@')
234
 
        self.assertEqual(osutils.kind_marker('tree-reference'), '+')
 
280
        self.assertEqual("", osutils.kind_marker("file"))
 
281
        self.assertEqual("/", osutils.kind_marker('directory'))
 
282
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
 
283
        self.assertEqual("@", osutils.kind_marker("symlink"))
 
284
        self.assertEqual("+", osutils.kind_marker("tree-reference"))
 
285
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
 
286
 
 
287
 
 
288
class TestUmask(tests.TestCaseInTempDir):
235
289
 
236
290
    def test_get_umask(self):
237
291
        if sys.platform == 'win32':
240
294
            return
241
295
 
242
296
        orig_umask = osutils.get_umask()
243
 
        try:
244
 
            os.umask(0222)
245
 
            self.assertEqual(0222, osutils.get_umask())
246
 
            os.umask(0022)
247
 
            self.assertEqual(0022, osutils.get_umask())
248
 
            os.umask(0002)
249
 
            self.assertEqual(0002, osutils.get_umask())
250
 
            os.umask(0027)
251
 
            self.assertEqual(0027, osutils.get_umask())
252
 
        finally:
253
 
            os.umask(orig_umask)
 
297
        self.addCleanup(os.umask, orig_umask)
 
298
        os.umask(0222)
 
299
        self.assertEqual(0222, osutils.get_umask())
 
300
        os.umask(0022)
 
301
        self.assertEqual(0022, osutils.get_umask())
 
302
        os.umask(0002)
 
303
        self.assertEqual(0002, osutils.get_umask())
 
304
        os.umask(0027)
 
305
        self.assertEqual(0027, osutils.get_umask())
 
306
 
 
307
 
 
308
class TestDateTime(tests.TestCase):
254
309
 
255
310
    def assertFormatedDelta(self, expected, seconds):
256
311
        """Assert osutils.format_delta formats as expected"""
298
353
        # Instead blackbox.test_locale should check for localized
299
354
        # dates once they do occur in output strings.
300
355
 
 
356
    def test_local_time_offset(self):
 
357
        """Test that local_time_offset() returns a sane value."""
 
358
        offset = osutils.local_time_offset()
 
359
        self.assertTrue(isinstance(offset, int))
 
360
        # Test that the offset is no more than a eighteen hours in
 
361
        # either direction.
 
362
        # Time zone handling is system specific, so it is difficult to
 
363
        # do more specific tests, but a value outside of this range is
 
364
        # probably wrong.
 
365
        eighteen_hours = 18 * 3600
 
366
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
367
 
 
368
    def test_local_time_offset_with_timestamp(self):
 
369
        """Test that local_time_offset() works with a timestamp."""
 
370
        offset = osutils.local_time_offset(1000000000.1234567)
 
371
        self.assertTrue(isinstance(offset, int))
 
372
        eighteen_hours = 18 * 3600
 
373
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
374
 
 
375
 
 
376
class TestLinks(tests.TestCaseInTempDir):
 
377
 
301
378
    def test_dereference_path(self):
302
 
        self.requireFeature(SymlinkFeature)
 
379
        self.requireFeature(tests.SymlinkFeature)
303
380
        cwd = osutils.realpath('.')
304
381
        os.mkdir('bar')
305
382
        bar_path = osutils.pathjoin(cwd, 'bar')
346
423
            osutils.make_readonly('dangling')
347
424
            osutils.make_writable('dangling')
348
425
 
349
 
    def test_kind_marker(self):
350
 
        self.assertEqual("", osutils.kind_marker("file"))
351
 
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
352
 
        self.assertEqual("@", osutils.kind_marker("symlink"))
353
 
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
354
 
 
355
426
    def test_host_os_dereferences_symlinks(self):
356
427
        osutils.host_os_dereferences_symlinks()
357
428
 
358
429
 
359
 
class TestCanonicalRelPath(TestCaseInTempDir):
 
430
class TestCanonicalRelPath(tests.TestCaseInTempDir):
360
431
 
361
 
    _test_needs_features = [CaseInsCasePresFilenameFeature]
 
432
    _test_needs_features = [tests.CaseInsCasePresFilenameFeature]
362
433
 
363
434
    def test_canonical_relpath_simple(self):
364
435
        f = file('MixedCaseName', 'w')
365
436
        f.close()
366
 
        self.failUnlessEqual(
367
 
            canonical_relpath(self.test_base_dir, 'mixedcasename'),
368
 
            'work/MixedCaseName')
 
437
        # Watch out for tricky test dir (on OSX /tmp -> /private/tmp)
 
438
        real_base_dir = osutils.realpath(self.test_base_dir)
 
439
        actual = osutils.canonical_relpath(real_base_dir, 'mixedcasename')
 
440
        self.failUnlessEqual('work/MixedCaseName', actual)
369
441
 
370
442
    def test_canonical_relpath_missing_tail(self):
371
443
        os.mkdir('MixedCaseParent')
372
 
        self.failUnlessEqual(
373
 
            canonical_relpath(self.test_base_dir, 'mixedcaseparent/nochild'),
374
 
            'work/MixedCaseParent/nochild')
375
 
 
376
 
 
377
 
class TestPumpFile(TestCase):
 
444
        # Watch out for tricky test dir (on OSX /tmp -> /private/tmp)
 
445
        real_base_dir = osutils.realpath(self.test_base_dir)
 
446
        actual = osutils.canonical_relpath(real_base_dir,
 
447
                                           'mixedcaseparent/nochild')
 
448
        self.failUnlessEqual('work/MixedCaseParent/nochild', actual)
 
449
 
 
450
 
 
451
class TestPumpFile(tests.TestCase):
378
452
    """Test pumpfile method."""
 
453
 
379
454
    def setUp(self):
380
 
        TestCase.setUp(self)
 
455
        tests.TestCase.setUp(self)
381
456
        # create a test datablock
382
457
        self.block_size = 512
383
458
        pattern = '0123456789ABCDEF'
390
465
        # make sure test data is larger than max read size
391
466
        self.assertTrue(self.test_data_len > self.block_size)
392
467
 
393
 
        from_file = FakeReadFile(self.test_data)
 
468
        from_file = file_utils.FakeReadFile(self.test_data)
394
469
        to_file = StringIO()
395
470
 
396
471
        # read (max / 2) bytes and verify read size wasn't affected
397
472
        num_bytes_to_read = self.block_size / 2
398
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
473
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
399
474
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
400
475
        self.assertEqual(from_file.get_read_count(), 1)
401
476
 
402
477
        # read (max) bytes and verify read size wasn't affected
403
478
        num_bytes_to_read = self.block_size
404
479
        from_file.reset_read_count()
405
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
480
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
406
481
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
407
482
        self.assertEqual(from_file.get_read_count(), 1)
408
483
 
409
484
        # read (max + 1) bytes and verify read size was limited
410
485
        num_bytes_to_read = self.block_size + 1
411
486
        from_file.reset_read_count()
412
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
487
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
413
488
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
414
489
        self.assertEqual(from_file.get_read_count(), 2)
415
490
 
416
491
        # finish reading the rest of the data
417
492
        num_bytes_to_read = self.test_data_len - to_file.tell()
418
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
493
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
419
494
 
420
495
        # report error if the data wasn't equal (we only report the size due
421
496
        # to the length of the data)
431
506
        self.assertTrue(self.test_data_len > self.block_size)
432
507
 
433
508
        # retrieve data in blocks
434
 
        from_file = FakeReadFile(self.test_data)
 
509
        from_file = file_utils.FakeReadFile(self.test_data)
435
510
        to_file = StringIO()
436
 
        pumpfile(from_file, to_file, self.test_data_len, self.block_size)
 
511
        osutils.pumpfile(from_file, to_file, self.test_data_len,
 
512
                         self.block_size)
437
513
 
438
514
        # verify read size was equal to the maximum read size
439
515
        self.assertTrue(from_file.get_max_read_size() > 0)
454
530
        self.assertTrue(self.test_data_len > self.block_size)
455
531
 
456
532
        # retrieve data to EOF
457
 
        from_file = FakeReadFile(self.test_data)
 
533
        from_file = file_utils.FakeReadFile(self.test_data)
458
534
        to_file = StringIO()
459
 
        pumpfile(from_file, to_file, -1, self.block_size)
 
535
        osutils.pumpfile(from_file, to_file, -1, self.block_size)
460
536
 
461
537
        # verify read size was equal to the maximum read size
462
538
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
474
550
        test verifies that any existing usages of pumpfile will not be broken
475
551
        with this new version."""
476
552
        # retrieve data using default (old) pumpfile method
477
 
        from_file = FakeReadFile(self.test_data)
 
553
        from_file = file_utils.FakeReadFile(self.test_data)
478
554
        to_file = StringIO()
479
 
        pumpfile(from_file, to_file)
 
555
        osutils.pumpfile(from_file, to_file)
480
556
 
481
557
        # report error if the data wasn't equal (we only report the size due
482
558
        # to the length of the data)
491
567
            activity.append((length, direction))
492
568
        from_file = StringIO(self.test_data)
493
569
        to_file = StringIO()
494
 
        pumpfile(from_file, to_file, buff_size=500,
495
 
                 report_activity=log_activity, direction='read')
 
570
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
571
                         report_activity=log_activity, direction='read')
496
572
        self.assertEqual([(500, 'read'), (500, 'read'), (500, 'read'),
497
573
                          (36, 'read')], activity)
498
574
 
499
575
        from_file = StringIO(self.test_data)
500
576
        to_file = StringIO()
501
577
        del activity[:]
502
 
        pumpfile(from_file, to_file, buff_size=500,
503
 
                 report_activity=log_activity, direction='write')
 
578
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
579
                         report_activity=log_activity, direction='write')
504
580
        self.assertEqual([(500, 'write'), (500, 'write'), (500, 'write'),
505
581
                          (36, 'write')], activity)
506
582
 
508
584
        from_file = StringIO(self.test_data)
509
585
        to_file = StringIO()
510
586
        del activity[:]
511
 
        pumpfile(from_file, to_file, buff_size=500, read_length=1028,
512
 
                 report_activity=log_activity, direction='read')
 
587
        osutils.pumpfile(from_file, to_file, buff_size=500, read_length=1028,
 
588
                         report_activity=log_activity, direction='read')
513
589
        self.assertEqual([(500, 'read'), (500, 'read'), (28, 'read')], activity)
514
590
 
515
591
 
516
592
 
517
 
class TestPumpStringFile(TestCase):
 
593
class TestPumpStringFile(tests.TestCase):
518
594
 
519
595
    def test_empty(self):
520
596
        output = StringIO()
521
 
        pump_string_file("", output)
 
597
        osutils.pump_string_file("", output)
522
598
        self.assertEqual("", output.getvalue())
523
599
 
524
600
    def test_more_than_segment_size(self):
525
601
        output = StringIO()
526
 
        pump_string_file("123456789", output, 2)
 
602
        osutils.pump_string_file("123456789", output, 2)
527
603
        self.assertEqual("123456789", output.getvalue())
528
604
 
529
605
    def test_segment_size(self):
530
606
        output = StringIO()
531
 
        pump_string_file("12", output, 2)
 
607
        osutils.pump_string_file("12", output, 2)
532
608
        self.assertEqual("12", output.getvalue())
533
609
 
534
610
    def test_segment_size_multiple(self):
535
611
        output = StringIO()
536
 
        pump_string_file("1234", output, 2)
 
612
        osutils.pump_string_file("1234", output, 2)
537
613
        self.assertEqual("1234", output.getvalue())
538
614
 
539
615
 
540
 
class TestSafeUnicode(TestCase):
 
616
class TestSafeUnicode(tests.TestCase):
541
617
 
542
618
    def test_from_ascii_string(self):
543
619
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
552
628
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
553
629
 
554
630
    def test_bad_utf8_string(self):
555
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
631
        self.assertRaises(errors.BzrBadParameterNotUnicode,
556
632
                          osutils.safe_unicode,
557
633
                          '\xbb\xbb')
558
634
 
559
635
 
560
 
class TestSafeUtf8(TestCase):
 
636
class TestSafeUtf8(tests.TestCase):
561
637
 
562
638
    def test_from_ascii_string(self):
563
639
        f = 'foobar'
573
649
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
574
650
 
575
651
    def test_bad_utf8_string(self):
576
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
652
        self.assertRaises(errors.BzrBadParameterNotUnicode,
577
653
                          osutils.safe_utf8, '\xbb\xbb')
578
654
 
579
655
 
580
 
class TestSafeRevisionId(TestCase):
 
656
class TestSafeRevisionId(tests.TestCase):
581
657
 
582
658
    def test_from_ascii_string(self):
583
659
        # this shouldn't give a warning because it's getting an ascii string
605
681
        self.assertEqual(None, osutils.safe_revision_id(None))
606
682
 
607
683
 
608
 
class TestSafeFileId(TestCase):
 
684
class TestSafeFileId(tests.TestCase):
609
685
 
610
686
    def test_from_ascii_string(self):
611
687
        self.assertEqual('foobar', osutils.safe_file_id('foobar'))
631
707
        self.assertEqual(None, osutils.safe_file_id(None))
632
708
 
633
709
 
634
 
class TestWin32Funcs(TestCase):
635
 
    """Test that the _win32 versions of os utilities return appropriate paths."""
 
710
class TestWin32Funcs(tests.TestCase):
 
711
    """Test that _win32 versions of os utilities return appropriate paths."""
636
712
 
637
713
    def test_abspath(self):
638
714
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
645
721
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
646
722
 
647
723
    def test_pathjoin(self):
648
 
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
649
 
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
650
 
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
651
 
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
652
 
        self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
653
 
        self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
 
724
        self.assertEqual('path/to/foo',
 
725
                         osutils._win32_pathjoin('path', 'to', 'foo'))
 
726
        self.assertEqual('C:/foo',
 
727
                         osutils._win32_pathjoin('path\\to', 'C:\\foo'))
 
728
        self.assertEqual('C:/foo',
 
729
                         osutils._win32_pathjoin('path/to', 'C:/foo'))
 
730
        self.assertEqual('path/to/foo',
 
731
                         osutils._win32_pathjoin('path/to/', 'foo'))
 
732
        self.assertEqual('/foo',
 
733
                         osutils._win32_pathjoin('C:/path/to/', '/foo'))
 
734
        self.assertEqual('/foo',
 
735
                         osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
654
736
 
655
737
    def test_normpath(self):
656
 
        self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
657
 
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
 
738
        self.assertEqual('path/to/foo',
 
739
                         osutils._win32_normpath(r'path\\from\..\to\.\foo'))
 
740
        self.assertEqual('path/to/foo',
 
741
                         osutils._win32_normpath('path//from/../to/./foo'))
658
742
 
659
743
    def test_getcwd(self):
660
744
        cwd = osutils._win32_getcwd()
689
773
        self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
690
774
 
691
775
 
692
 
class TestWin32FuncsDirs(TestCaseInTempDir):
 
776
class TestWin32FuncsDirs(tests.TestCaseInTempDir):
693
777
    """Test win32 functions that create files."""
694
778
 
695
779
    def test_getcwd(self):
696
 
        if win32utils.winver == 'Windows 98':
697
 
            raise TestSkipped('Windows 98 cannot handle unicode filenames')
698
 
        # Make sure getcwd can handle unicode filenames
699
 
        try:
700
 
            os.mkdir(u'mu-\xb5')
701
 
        except UnicodeError:
702
 
            raise TestSkipped("Unable to create Unicode filename")
703
 
 
 
780
        self.requireFeature(tests.UnicodeFilenameFeature)
 
781
        os.mkdir(u'mu-\xb5')
704
782
        os.chdir(u'mu-\xb5')
705
783
        # TODO: jam 20060427 This will probably fail on Mac OSX because
706
784
        #       it will change the normalization of B\xe5gfors
711
789
    def test_minimum_path_selection(self):
712
790
        self.assertEqual(set(),
713
791
            osutils.minimum_path_selection([]))
 
792
        self.assertEqual(set(['a']),
 
793
            osutils.minimum_path_selection(['a']))
714
794
        self.assertEqual(set(['a', 'b']),
715
795
            osutils.minimum_path_selection(['a', 'b']))
716
796
        self.assertEqual(set(['a/', 'b']),
717
797
            osutils.minimum_path_selection(['a/', 'b']))
718
798
        self.assertEqual(set(['a/', 'b']),
719
799
            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
 
800
        self.assertEqual(set(['a-b', 'a', 'a0b']),
 
801
            osutils.minimum_path_selection(['a-b', 'a/b', 'a0b', 'a']))
720
802
 
721
803
    def test_mkdtemp(self):
722
804
        tmpdir = osutils._win32_mkdtemp(dir='.')
778
860
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
779
861
 
780
862
 
781
 
class TestMacFuncsDirs(TestCaseInTempDir):
 
863
class TestParentDirectories(tests.TestCaseInTempDir):
 
864
    """Test osutils.parent_directories()"""
 
865
 
 
866
    def test_parent_directories(self):
 
867
        self.assertEqual([], osutils.parent_directories('a'))
 
868
        self.assertEqual(['a'], osutils.parent_directories('a/b'))
 
869
        self.assertEqual(['a/b', 'a'], osutils.parent_directories('a/b/c'))
 
870
 
 
871
 
 
872
class TestMacFuncsDirs(tests.TestCaseInTempDir):
782
873
    """Test mac special functions that require directories."""
783
874
 
784
875
    def test_getcwd(self):
785
 
        # On Mac, this will actually create Ba\u030agfors
786
 
        # but chdir will still work, because it accepts both paths
787
 
        try:
788
 
            os.mkdir(u'B\xe5gfors')
789
 
        except UnicodeError:
790
 
            raise TestSkipped("Unable to create Unicode filename")
791
 
 
 
876
        self.requireFeature(tests.UnicodeFilenameFeature)
 
877
        os.mkdir(u'B\xe5gfors')
792
878
        os.chdir(u'B\xe5gfors')
793
879
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
794
880
 
795
881
    def test_getcwd_nonnorm(self):
 
882
        self.requireFeature(tests.UnicodeFilenameFeature)
796
883
        # Test that _mac_getcwd() will normalize this path
797
 
        try:
798
 
            os.mkdir(u'Ba\u030agfors')
799
 
        except UnicodeError:
800
 
            raise TestSkipped("Unable to create Unicode filename")
801
 
 
 
884
        os.mkdir(u'Ba\u030agfors')
802
885
        os.chdir(u'Ba\u030agfors')
803
886
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
804
887
 
805
888
 
806
 
class TestChunksToLines(TestCase):
 
889
class TestChunksToLines(tests.TestCase):
807
890
 
808
891
    def test_smoketest(self):
809
892
        self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
820
903
        self.assertIs(chunks_to_lines, osutils.chunks_to_lines)
821
904
 
822
905
 
823
 
class TestSplitLines(TestCase):
 
906
class TestSplitLines(tests.TestCase):
824
907
 
825
908
    def test_split_unicode(self):
826
909
        self.assertEqual([u'foo\n', u'bar\xae'],
833
916
                         osutils.split_lines('foo\rbar\n'))
834
917
 
835
918
 
836
 
class TestWalkDirs(TestCaseInTempDir):
 
919
class TestWalkDirs(tests.TestCaseInTempDir):
 
920
 
 
921
    def assertExpectedBlocks(self, expected, result):
 
922
        self.assertEqual(expected,
 
923
                         [(dirinfo, [line[0:3] for line in block])
 
924
                          for dirinfo, block in result])
837
925
 
838
926
    def test_walkdirs(self):
839
927
        tree = [
872
960
            result.append((dirdetail, dirblock))
873
961
 
874
962
        self.assertTrue(found_bzrdir)
875
 
        self.assertEqual(expected_dirblocks,
876
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
963
        self.assertExpectedBlocks(expected_dirblocks, result)
877
964
        # you can search a subdir only, with a supplied prefix.
878
965
        result = []
879
966
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
880
967
            result.append(dirblock)
881
 
        self.assertEqual(expected_dirblocks[1:],
882
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
968
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
883
969
 
884
970
    def test_walkdirs_os_error(self):
885
971
        # <https://bugs.edge.launchpad.net/bzr/+bug/338653>
891
977
        os.mkdir("test-unreadable")
892
978
        os.chmod("test-unreadable", 0000)
893
979
        # must chmod it back so that it can be removed
894
 
        self.addCleanup(lambda: os.chmod("test-unreadable", 0700))
 
980
        self.addCleanup(os.chmod, "test-unreadable", 0700)
895
981
        # The error is not raised until the generator is actually evaluated.
896
982
        # (It would be ok if it happened earlier but at the moment it
897
983
        # doesn't.)
938
1024
            result.append((dirdetail, dirblock))
939
1025
 
940
1026
        self.assertTrue(found_bzrdir)
941
 
        self.assertEqual(expected_dirblocks,
942
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1027
        self.assertExpectedBlocks(expected_dirblocks, result)
 
1028
 
943
1029
        # you can search a subdir only, with a supplied prefix.
944
1030
        result = []
945
1031
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
946
1032
            result.append(dirblock)
947
 
        self.assertEqual(expected_dirblocks[1:],
948
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1033
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
949
1034
 
950
1035
    def _filter_out_stat(self, result):
951
1036
        """Filter out the stat value from the walkdirs result"""
966
1051
            osutils._selected_dir_reader = cur_dir_reader
967
1052
        self.addCleanup(restore)
968
1053
 
969
 
    def assertReadFSDirIs(self, expected):
 
1054
    def assertDirReaderIs(self, expected):
970
1055
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
971
1056
        # Force it to redetect
972
1057
        osutils._selected_dir_reader = None
979
1064
        self._save_platform_info()
980
1065
        win32utils.winver = None # Avoid the win32 detection code
981
1066
        osutils._fs_enc = 'UTF-8'
982
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1067
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
983
1068
 
984
1069
    def test_force_walkdirs_utf8_fs_ascii(self):
985
1070
        self.requireFeature(UTF8DirReaderFeature)
986
1071
        self._save_platform_info()
987
1072
        win32utils.winver = None # Avoid the win32 detection code
988
1073
        osutils._fs_enc = 'US-ASCII'
989
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1074
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
990
1075
 
991
1076
    def test_force_walkdirs_utf8_fs_ANSI(self):
992
1077
        self.requireFeature(UTF8DirReaderFeature)
993
1078
        self._save_platform_info()
994
1079
        win32utils.winver = None # Avoid the win32 detection code
995
1080
        osutils._fs_enc = 'ANSI_X3.4-1968'
996
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1081
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
997
1082
 
998
1083
    def test_force_walkdirs_utf8_fs_latin1(self):
999
1084
        self._save_platform_info()
1000
1085
        win32utils.winver = None # Avoid the win32 detection code
1001
1086
        osutils._fs_enc = 'latin1'
1002
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1087
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1003
1088
 
1004
1089
    def test_force_walkdirs_utf8_nt(self):
1005
1090
        # Disabled because the thunk of the whole walkdirs api is disabled.
1006
 
        self.requireFeature(Win32ReadDirFeature)
 
1091
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
1007
1092
        self._save_platform_info()
1008
1093
        win32utils.winver = 'Windows NT'
1009
1094
        from bzrlib._walkdirs_win32 import Win32ReadDir
1010
 
        self.assertReadFSDirIs(Win32ReadDir)
 
1095
        self.assertDirReaderIs(Win32ReadDir)
1011
1096
 
1012
1097
    def test_force_walkdirs_utf8_98(self):
1013
 
        self.requireFeature(Win32ReadDirFeature)
 
1098
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
1014
1099
        self._save_platform_info()
1015
1100
        win32utils.winver = 'Windows 98'
1016
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1101
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1017
1102
 
1018
1103
    def test_unicode_walkdirs(self):
1019
1104
        """Walkdirs should always return unicode paths."""
 
1105
        self.requireFeature(tests.UnicodeFilenameFeature)
1020
1106
        name0 = u'0file-\xb6'
1021
1107
        name1 = u'1dir-\u062c\u0648'
1022
1108
        name2 = u'2file-\u0633'
1027
1113
            name1 + '/' + name1 + '/',
1028
1114
            name2,
1029
1115
            ]
1030
 
        try:
1031
 
            self.build_tree(tree)
1032
 
        except UnicodeError:
1033
 
            raise TestSkipped('Could not represent Unicode chars'
1034
 
                              ' in current encoding.')
 
1116
        self.build_tree(tree)
1035
1117
        expected_dirblocks = [
1036
1118
                ((u'', u'.'),
1037
1119
                 [(name0, name0, 'file', './' + name0),
1063
1145
 
1064
1146
        The abspath portion might be in unicode or utf-8
1065
1147
        """
 
1148
        self.requireFeature(tests.UnicodeFilenameFeature)
1066
1149
        name0 = u'0file-\xb6'
1067
1150
        name1 = u'1dir-\u062c\u0648'
1068
1151
        name2 = u'2file-\u0633'
1073
1156
            name1 + '/' + name1 + '/',
1074
1157
            name2,
1075
1158
            ]
1076
 
        try:
1077
 
            self.build_tree(tree)
1078
 
        except UnicodeError:
1079
 
            raise TestSkipped('Could not represent Unicode chars'
1080
 
                              ' in current encoding.')
 
1159
        self.build_tree(tree)
1081
1160
        name0 = name0.encode('utf8')
1082
1161
        name1 = name1.encode('utf8')
1083
1162
        name2 = name2.encode('utf8')
1127
1206
 
1128
1207
        The abspath portion should be in unicode
1129
1208
        """
 
1209
        self.requireFeature(tests.UnicodeFilenameFeature)
1130
1210
        # Use the unicode reader. TODO: split into driver-and-driven unit
1131
1211
        # tests.
1132
1212
        self._save_platform_info()
1141
1221
            name1u + '/' + name1u + '/',
1142
1222
            name2u,
1143
1223
            ]
1144
 
        try:
1145
 
            self.build_tree(tree)
1146
 
        except UnicodeError:
1147
 
            raise TestSkipped('Could not represent Unicode chars'
1148
 
                              ' in current encoding.')
 
1224
        self.build_tree(tree)
1149
1225
        name0 = name0u.encode('utf8')
1150
1226
        name1 = name1u.encode('utf8')
1151
1227
        name2 = name2u.encode('utf8')
1176
1252
        self.assertEqual(expected_dirblocks, result)
1177
1253
 
1178
1254
    def test__walkdirs_utf8_win32readdir(self):
1179
 
        self.requireFeature(Win32ReadDirFeature)
 
1255
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
1180
1256
        self.requireFeature(tests.UnicodeFilenameFeature)
1181
1257
        from bzrlib._walkdirs_win32 import Win32ReadDir
1182
1258
        self._save_platform_info()
1233
1309
 
1234
1310
    def test__walkdirs_utf_win32_find_file_stat_file(self):
1235
1311
        """make sure our Stat values are valid"""
1236
 
        self.requireFeature(Win32ReadDirFeature)
 
1312
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
1237
1313
        self.requireFeature(tests.UnicodeFilenameFeature)
1238
1314
        from bzrlib._walkdirs_win32 import Win32ReadDir
1239
1315
        name0u = u'0file-\xb6'
1257
1333
 
1258
1334
    def test__walkdirs_utf_win32_find_file_stat_directory(self):
1259
1335
        """make sure our Stat values are valid"""
1260
 
        self.requireFeature(Win32ReadDirFeature)
 
1336
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
1261
1337
        self.requireFeature(tests.UnicodeFilenameFeature)
1262
1338
        from bzrlib._walkdirs_win32 import Win32ReadDir
1263
1339
        name0u = u'0dir-\u062c\u0648'
1348
1424
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1349
1425
 
1350
1426
 
1351
 
class TestCopyTree(TestCaseInTempDir):
 
1427
class TestCopyTree(tests.TestCaseInTempDir):
1352
1428
 
1353
1429
    def test_copy_basic_tree(self):
1354
1430
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1364
1440
        self.assertEqual(['c'], os.listdir('target/b'))
1365
1441
 
1366
1442
    def test_copy_tree_symlinks(self):
1367
 
        self.requireFeature(SymlinkFeature)
 
1443
        self.requireFeature(tests.SymlinkFeature)
1368
1444
        self.build_tree(['source/'])
1369
1445
        os.symlink('a/generic/path', 'source/lnk')
1370
1446
        osutils.copy_tree('source', 'target')
1400
1476
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1401
1477
 
1402
1478
 
1403
 
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
1404
 
# [bialix] 2006/12/26
1405
 
 
1406
 
 
1407
 
class TestSetUnsetEnv(TestCase):
 
1479
class TestSetUnsetEnv(tests.TestCase):
1408
1480
    """Test updating the environment"""
1409
1481
 
1410
1482
    def setUp(self):
1437
1509
 
1438
1510
        So Unicode strings must be encoded.
1439
1511
        """
1440
 
        uni_val, env_val = probe_unicode_in_user_encoding()
 
1512
        uni_val, env_val = tests.probe_unicode_in_user_encoding()
1441
1513
        if uni_val is None:
1442
 
            raise TestSkipped('Cannot find a unicode character that works in'
1443
 
                              ' encoding %s' % (osutils.get_user_encoding(),))
 
1514
            raise tests.TestSkipped(
 
1515
                'Cannot find a unicode character that works in encoding %s'
 
1516
                % (osutils.get_user_encoding(),))
1444
1517
 
1445
1518
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1446
1519
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1454
1527
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1455
1528
 
1456
1529
 
1457
 
class TestLocalTimeOffset(TestCase):
1458
 
 
1459
 
    def test_local_time_offset(self):
1460
 
        """Test that local_time_offset() returns a sane value."""
1461
 
        offset = osutils.local_time_offset()
1462
 
        self.assertTrue(isinstance(offset, int))
1463
 
        # Test that the offset is no more than a eighteen hours in
1464
 
        # either direction.
1465
 
        # Time zone handling is system specific, so it is difficult to
1466
 
        # do more specific tests, but a value outside of this range is
1467
 
        # probably wrong.
1468
 
        eighteen_hours = 18 * 3600
1469
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1470
 
 
1471
 
    def test_local_time_offset_with_timestamp(self):
1472
 
        """Test that local_time_offset() works with a timestamp."""
1473
 
        offset = osutils.local_time_offset(1000000000.1234567)
1474
 
        self.assertTrue(isinstance(offset, int))
1475
 
        eighteen_hours = 18 * 3600
1476
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1477
 
 
1478
 
 
1479
 
class TestSizeShaFile(TestCaseInTempDir):
 
1530
class TestSizeShaFile(tests.TestCaseInTempDir):
1480
1531
 
1481
1532
    def test_sha_empty(self):
1482
1533
        self.build_tree_contents([('foo', '')])
1498
1549
        self.assertEqual(expected_sha, sha)
1499
1550
 
1500
1551
 
1501
 
class TestShaFileByName(TestCaseInTempDir):
 
1552
class TestShaFileByName(tests.TestCaseInTempDir):
1502
1553
 
1503
1554
    def test_sha_empty(self):
1504
1555
        self.build_tree_contents([('foo', '')])
1512
1563
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1513
1564
 
1514
1565
 
1515
 
class TestResourceLoading(TestCaseInTempDir):
 
1566
class TestResourceLoading(tests.TestCaseInTempDir):
1516
1567
 
1517
1568
    def test_resource_string(self):
1518
1569
        # test resource in bzrlib
1528
1579
        self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')
1529
1580
 
1530
1581
 
1531
 
class TestReCompile(TestCase):
 
1582
class TestReCompile(tests.TestCase):
1532
1583
 
1533
1584
    def test_re_compile_checked(self):
1534
1585
        r = osutils.re_compile_checked(r'A*', re.IGNORECASE)
1544
1595
            "Invalid regular expression in test case: '*': "
1545
1596
            "nothing to repeat",
1546
1597
            str(err))
 
1598
 
 
1599
 
 
1600
class TestDirReader(tests.TestCaseInTempDir):
 
1601
 
 
1602
    # Set by load_tests
 
1603
    _dir_reader_class = None
 
1604
    _native_to_unicode = None
 
1605
 
 
1606
    def setUp(self):
 
1607
        tests.TestCaseInTempDir.setUp(self)
 
1608
 
 
1609
        # Save platform specific info and reset it
 
1610
        cur_dir_reader = osutils._selected_dir_reader
 
1611
 
 
1612
        def restore():
 
1613
            osutils._selected_dir_reader = cur_dir_reader
 
1614
        self.addCleanup(restore)
 
1615
 
 
1616
        osutils._selected_dir_reader = self._dir_reader_class()
 
1617
 
 
1618
    def _get_ascii_tree(self):
 
1619
        tree = [
 
1620
            '0file',
 
1621
            '1dir/',
 
1622
            '1dir/0file',
 
1623
            '1dir/1dir/',
 
1624
            '2file'
 
1625
            ]
 
1626
        expected_dirblocks = [
 
1627
                (('', '.'),
 
1628
                 [('0file', '0file', 'file'),
 
1629
                  ('1dir', '1dir', 'directory'),
 
1630
                  ('2file', '2file', 'file'),
 
1631
                 ]
 
1632
                ),
 
1633
                (('1dir', './1dir'),
 
1634
                 [('1dir/0file', '0file', 'file'),
 
1635
                  ('1dir/1dir', '1dir', 'directory'),
 
1636
                 ]
 
1637
                ),
 
1638
                (('1dir/1dir', './1dir/1dir'),
 
1639
                 [
 
1640
                 ]
 
1641
                ),
 
1642
            ]
 
1643
        return tree, expected_dirblocks
 
1644
 
 
1645
    def test_walk_cur_dir(self):
 
1646
        tree, expected_dirblocks = self._get_ascii_tree()
 
1647
        self.build_tree(tree)
 
1648
        result = list(osutils._walkdirs_utf8('.'))
 
1649
        # Filter out stat and abspath
 
1650
        self.assertEqual(expected_dirblocks,
 
1651
                         [(dirinfo, [line[0:3] for line in block])
 
1652
                          for dirinfo, block in result])
 
1653
 
 
1654
    def test_walk_sub_dir(self):
 
1655
        tree, expected_dirblocks = self._get_ascii_tree()
 
1656
        self.build_tree(tree)
 
1657
        # you can search a subdir only, with a supplied prefix.
 
1658
        result = list(osutils._walkdirs_utf8('./1dir', '1dir'))
 
1659
        # Filter out stat and abspath
 
1660
        self.assertEqual(expected_dirblocks[1:],
 
1661
                         [(dirinfo, [line[0:3] for line in block])
 
1662
                          for dirinfo, block in result])
 
1663
 
 
1664
    def _get_unicode_tree(self):
 
1665
        name0u = u'0file-\xb6'
 
1666
        name1u = u'1dir-\u062c\u0648'
 
1667
        name2u = u'2file-\u0633'
 
1668
        tree = [
 
1669
            name0u,
 
1670
            name1u + '/',
 
1671
            name1u + '/' + name0u,
 
1672
            name1u + '/' + name1u + '/',
 
1673
            name2u,
 
1674
            ]
 
1675
        name0 = name0u.encode('UTF-8')
 
1676
        name1 = name1u.encode('UTF-8')
 
1677
        name2 = name2u.encode('UTF-8')
 
1678
        expected_dirblocks = [
 
1679
                (('', '.'),
 
1680
                 [(name0, name0, 'file', './' + name0u),
 
1681
                  (name1, name1, 'directory', './' + name1u),
 
1682
                  (name2, name2, 'file', './' + name2u),
 
1683
                 ]
 
1684
                ),
 
1685
                ((name1, './' + name1u),
 
1686
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1687
                                                        + '/' + name0u),
 
1688
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1689
                                                            + '/' + name1u),
 
1690
                 ]
 
1691
                ),
 
1692
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1693
                 [
 
1694
                 ]
 
1695
                ),
 
1696
            ]
 
1697
        return tree, expected_dirblocks
 
1698
 
 
1699
    def _filter_out(self, raw_dirblocks):
 
1700
        """Filter out a walkdirs_utf8 result.
 
1701
 
 
1702
        stat field is removed, all native paths are converted to unicode
 
1703
        """
 
1704
        filtered_dirblocks = []
 
1705
        for dirinfo, block in raw_dirblocks:
 
1706
            dirinfo = (dirinfo[0], self._native_to_unicode(dirinfo[1]))
 
1707
            details = []
 
1708
            for line in block:
 
1709
                details.append(line[0:3] + (self._native_to_unicode(line[4]), ))
 
1710
            filtered_dirblocks.append((dirinfo, details))
 
1711
        return filtered_dirblocks
 
1712
 
 
1713
    def test_walk_unicode_tree(self):
 
1714
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1715
        tree, expected_dirblocks = self._get_unicode_tree()
 
1716
        self.build_tree(tree)
 
1717
        result = list(osutils._walkdirs_utf8('.'))
 
1718
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1719
 
 
1720
    def test_symlink(self):
 
1721
        self.requireFeature(tests.SymlinkFeature)
 
1722
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1723
        target = u'target\N{Euro Sign}'
 
1724
        link_name = u'l\N{Euro Sign}nk'
 
1725
        os.symlink(target, link_name)
 
1726
        target_utf8 = target.encode('UTF-8')
 
1727
        link_name_utf8 = link_name.encode('UTF-8')
 
1728
        expected_dirblocks = [
 
1729
                (('', '.'),
 
1730
                 [(link_name_utf8, link_name_utf8,
 
1731
                   'symlink', './' + link_name),],
 
1732
                 )]
 
1733
        result = list(osutils._walkdirs_utf8('.'))
 
1734
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1735
 
 
1736
 
 
1737
class TestReadLink(tests.TestCaseInTempDir):
 
1738
    """Exposes os.readlink() problems and the osutils solution.
 
1739
 
 
1740
    The only guarantee offered by os.readlink(), starting with 2.6, is that a
 
1741
    unicode string will be returned if a unicode string is passed.
 
1742
 
 
1743
    But prior python versions failed to properly encode the passed unicode
 
1744
    string.
 
1745
    """
 
1746
    _test_needs_features = [tests.SymlinkFeature, tests.UnicodeFilenameFeature]
 
1747
 
 
1748
    def setUp(self):
 
1749
        super(tests.TestCaseInTempDir, self).setUp()
 
1750
        self.link = u'l\N{Euro Sign}ink'
 
1751
        self.target = u'targe\N{Euro Sign}t'
 
1752
        os.symlink(self.target, self.link)
 
1753
 
 
1754
    def test_os_readlink_link_encoding(self):
 
1755
        if sys.version_info < (2, 6):
 
1756
            self.assertRaises(UnicodeEncodeError, os.readlink, self.link)
 
1757
        else:
 
1758
            self.assertEquals(self.target,  os.readlink(self.link))
 
1759
 
 
1760
    def test_os_readlink_link_decoding(self):
 
1761
        self.assertEquals(self.target.encode(osutils._fs_enc),
 
1762
                          os.readlink(self.link.encode(osutils._fs_enc)))