/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: Robert Collins
  • Date: 2008-08-20 02:07:36 UTC
  • mfrom: (3640 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20080820020736-g2xe4921zzxtymle
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
"""Tests for the osutils wrapper."""
18
18
 
 
19
from cStringIO import StringIO
19
20
import errno
20
21
import os
21
22
import socket
22
23
import stat
23
24
import sys
 
25
import time
24
26
 
25
27
import bzrlib
 
28
from bzrlib import (
 
29
    errors,
 
30
    osutils,
 
31
    readdir,
 
32
    tests,
 
33
    win32utils,
 
34
    )
26
35
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
27
 
import bzrlib.osutils as osutils
28
 
import bzrlib.readdir as readdir
29
 
from bzrlib.tests import TestCaseInTempDir, TestCase, TestSkipped
 
36
from bzrlib.osutils import (
 
37
        is_inside_any,
 
38
        is_inside_or_parent_of_any,
 
39
        pathjoin,
 
40
        pumpfile,
 
41
        )
 
42
from bzrlib.tests import (
 
43
        probe_unicode_in_user_encoding,
 
44
        StringIOWrapper,
 
45
        SymlinkFeature,
 
46
        TestCase,
 
47
        TestCaseInTempDir,
 
48
        TestSkipped,
 
49
        )
 
50
from bzrlib.tests.file_utils import (
 
51
    FakeReadFile,
 
52
    )
 
53
from bzrlib.tests.test__walkdirs_win32 import WalkdirsWin32Feature
30
54
 
31
55
 
32
56
class TestOSUtils(TestCaseInTempDir):
33
57
 
 
58
    def test_contains_whitespace(self):
 
59
        self.failUnless(osutils.contains_whitespace(u' '))
 
60
        self.failUnless(osutils.contains_whitespace(u'hello there'))
 
61
        self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
 
62
        self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
 
63
        self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
 
64
        self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
 
65
 
 
66
        # \xa0 is "Non-breaking-space" which on some python locales thinks it
 
67
        # is whitespace, but we do not.
 
68
        self.failIf(osutils.contains_whitespace(u''))
 
69
        self.failIf(osutils.contains_whitespace(u'hellothere'))
 
70
        self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
 
71
 
34
72
    def test_fancy_rename(self):
35
73
        # This should work everywhere
36
74
        def rename(a, b):
64
102
 
65
103
    # TODO: test fancy_rename using a MemoryTransport
66
104
 
 
105
    def test_rename_change_case(self):
 
106
        # on Windows we should be able to change filename case by rename
 
107
        self.build_tree(['a', 'b/'])
 
108
        osutils.rename('a', 'A')
 
109
        osutils.rename('b', 'B')
 
110
        # we can't use failUnlessExists on case-insensitive filesystem
 
111
        # so try to check shape of the tree
 
112
        shape = sorted(os.listdir('.'))
 
113
        self.assertEquals(['A', 'B'], shape)
 
114
 
67
115
    def test_01_rand_chars_empty(self):
68
116
        result = osutils.rand_chars(0)
69
117
        self.assertEqual(result, '')
74
122
        self.assertEqual(type(result), str)
75
123
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
76
124
 
 
125
    def test_is_inside(self):
 
126
        is_inside = osutils.is_inside
 
127
        self.assertTrue(is_inside('src', 'src/foo.c'))
 
128
        self.assertFalse(is_inside('src', 'srccontrol'))
 
129
        self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
 
130
        self.assertTrue(is_inside('foo.c', 'foo.c'))
 
131
        self.assertFalse(is_inside('foo.c', ''))
 
132
        self.assertTrue(is_inside('', 'foo.c'))
 
133
 
 
134
    def test_is_inside_any(self):
 
135
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
136
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
 
137
                         (['src'], SRC_FOO_C),
 
138
                         (['src'], 'src'),
 
139
                         ]:
 
140
            self.assert_(is_inside_any(dirs, fn))
 
141
        for dirs, fn in [(['src'], 'srccontrol'),
 
142
                         (['src'], 'srccontrol/foo')]:
 
143
            self.assertFalse(is_inside_any(dirs, fn))
 
144
 
 
145
    def test_is_inside_or_parent_of_any(self):
 
146
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
 
147
                         (['src'], 'src/foo.c'),
 
148
                         (['src/bar.c'], 'src'),
 
149
                         (['src/bar.c', 'bla/foo.c'], 'src'),
 
150
                         (['src'], 'src'),
 
151
                         ]:
 
152
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
 
153
            
 
154
        for dirs, fn in [(['src'], 'srccontrol'),
 
155
                         (['srccontrol/foo.c'], 'src'),
 
156
                         (['src'], 'srccontrol/foo')]:
 
157
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
77
158
 
78
159
    def test_rmtree(self):
79
160
        # Check to remove tree with read-only files/dirs
127
208
            finally:
128
209
                os.remove('socket')
129
210
 
 
211
    def test_kind_marker(self):
 
212
        self.assertEqual(osutils.kind_marker('file'), '')
 
213
        self.assertEqual(osutils.kind_marker('directory'), '/')
 
214
        self.assertEqual(osutils.kind_marker('symlink'), '@')
 
215
        self.assertEqual(osutils.kind_marker('tree-reference'), '+')
 
216
 
 
217
    def test_get_umask(self):
 
218
        if sys.platform == 'win32':
 
219
            # umask always returns '0', no way to set it
 
220
            self.assertEqual(0, osutils.get_umask())
 
221
            return
 
222
 
 
223
        orig_umask = osutils.get_umask()
 
224
        try:
 
225
            os.umask(0222)
 
226
            self.assertEqual(0222, osutils.get_umask())
 
227
            os.umask(0022)
 
228
            self.assertEqual(0022, osutils.get_umask())
 
229
            os.umask(0002)
 
230
            self.assertEqual(0002, osutils.get_umask())
 
231
            os.umask(0027)
 
232
            self.assertEqual(0027, osutils.get_umask())
 
233
        finally:
 
234
            os.umask(orig_umask)
 
235
 
 
236
    def assertFormatedDelta(self, expected, seconds):
 
237
        """Assert osutils.format_delta formats as expected"""
 
238
        actual = osutils.format_delta(seconds)
 
239
        self.assertEqual(expected, actual)
 
240
 
 
241
    def test_format_delta(self):
 
242
        self.assertFormatedDelta('0 seconds ago', 0)
 
243
        self.assertFormatedDelta('1 second ago', 1)
 
244
        self.assertFormatedDelta('10 seconds ago', 10)
 
245
        self.assertFormatedDelta('59 seconds ago', 59)
 
246
        self.assertFormatedDelta('89 seconds ago', 89)
 
247
        self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
 
248
        self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
 
249
        self.assertFormatedDelta('3 minutes, 1 second ago', 181)
 
250
        self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
 
251
        self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
 
252
        self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
 
253
        self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
 
254
        self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
 
255
        self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
 
256
        self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
 
257
        self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
 
258
        self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
 
259
        self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
 
260
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
 
261
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
 
262
        self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
 
263
        self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
 
264
        self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
 
265
 
 
266
        # We handle when time steps the wrong direction because computers
 
267
        # don't have synchronized clocks.
 
268
        self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
 
269
        self.assertFormatedDelta('1 second in the future', -1)
 
270
        self.assertFormatedDelta('2 seconds in the future', -2)
 
271
 
 
272
    def test_format_date(self):
 
273
        self.assertRaises(errors.UnsupportedTimezoneFormat,
 
274
            osutils.format_date, 0, timezone='foo')
 
275
 
 
276
    def test_dereference_path(self):
 
277
        self.requireFeature(SymlinkFeature)
 
278
        cwd = osutils.realpath('.')
 
279
        os.mkdir('bar')
 
280
        bar_path = osutils.pathjoin(cwd, 'bar')
 
281
        # Using './' to avoid bug #1213894 (first path component not
 
282
        # dereferenced) in Python 2.4.1 and earlier
 
283
        self.assertEqual(bar_path, osutils.realpath('./bar'))
 
284
        os.symlink('bar', 'foo')
 
285
        self.assertEqual(bar_path, osutils.realpath('./foo'))
 
286
        
 
287
        # Does not dereference terminal symlinks
 
288
        foo_path = osutils.pathjoin(cwd, 'foo')
 
289
        self.assertEqual(foo_path, osutils.dereference_path('./foo'))
 
290
 
 
291
        # Dereferences parent symlinks
 
292
        os.mkdir('bar/baz')
 
293
        baz_path = osutils.pathjoin(bar_path, 'baz')
 
294
        self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
 
295
 
 
296
        # Dereferences parent symlinks that are the first path element
 
297
        self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
 
298
 
 
299
        # Dereferences parent symlinks in absolute paths
 
300
        foo_baz_path = osutils.pathjoin(foo_path, 'baz')
 
301
        self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
 
302
 
 
303
    def test_changing_access(self):
 
304
        f = file('file', 'w')
 
305
        f.write('monkey')
 
306
        f.close()
 
307
 
 
308
        # Make a file readonly
 
309
        osutils.make_readonly('file')
 
310
        mode = os.lstat('file').st_mode
 
311
        self.assertEqual(mode, mode & 0777555)
 
312
 
 
313
        # Make a file writable
 
314
        osutils.make_writable('file')
 
315
        mode = os.lstat('file').st_mode
 
316
        self.assertEqual(mode, mode | 0200)
 
317
 
 
318
        if osutils.has_symlinks():
 
319
            # should not error when handed a symlink
 
320
            os.symlink('nonexistent', 'dangling')
 
321
            osutils.make_readonly('dangling')
 
322
            osutils.make_writable('dangling')
 
323
 
 
324
    def test_kind_marker(self):
 
325
        self.assertEqual("", osutils.kind_marker("file"))
 
326
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
 
327
        self.assertEqual("@", osutils.kind_marker("symlink"))
 
328
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
 
329
 
 
330
    def test_host_os_dereferences_symlinks(self):
 
331
        osutils.host_os_dereferences_symlinks()
 
332
 
 
333
 
 
334
class TestPumpFile(TestCase):
 
335
    """Test pumpfile method."""
 
336
    def setUp(self):
 
337
        # create a test datablock
 
338
        self.block_size = 512
 
339
        pattern = '0123456789ABCDEF'
 
340
        self.test_data = pattern * (3 * self.block_size / len(pattern))
 
341
        self.test_data_len = len(self.test_data)
 
342
 
 
343
    def test_bracket_block_size(self):
 
344
        """Read data in blocks with the requested read size bracketing the
 
345
        block size."""
 
346
        # make sure test data is larger than max read size
 
347
        self.assertTrue(self.test_data_len > self.block_size)
 
348
 
 
349
        from_file = FakeReadFile(self.test_data)
 
350
        to_file = StringIO()
 
351
 
 
352
        # read (max / 2) bytes and verify read size wasn't affected
 
353
        num_bytes_to_read = self.block_size / 2
 
354
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
355
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
 
356
        self.assertEqual(from_file.get_read_count(), 1)
 
357
 
 
358
        # read (max) bytes and verify read size wasn't affected
 
359
        num_bytes_to_read = self.block_size
 
360
        from_file.reset_read_count()
 
361
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
362
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
 
363
        self.assertEqual(from_file.get_read_count(), 1)
 
364
 
 
365
        # read (max + 1) bytes and verify read size was limited
 
366
        num_bytes_to_read = self.block_size + 1
 
367
        from_file.reset_read_count()
 
368
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
369
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
 
370
        self.assertEqual(from_file.get_read_count(), 2)
 
371
 
 
372
        # finish reading the rest of the data
 
373
        num_bytes_to_read = self.test_data_len - to_file.tell()
 
374
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
375
 
 
376
        # report error if the data wasn't equal (we only report the size due
 
377
        # to the length of the data)
 
378
        response_data = to_file.getvalue()
 
379
        if response_data != self.test_data:
 
380
            message = "Data not equal.  Expected %d bytes, received %d."
 
381
            self.fail(message % (len(response_data), self.test_data_len))
 
382
 
 
383
    def test_specified_size(self):
 
384
        """Request a transfer larger than the maximum block size and verify
 
385
        that the maximum read doesn't exceed the block_size."""
 
386
        # make sure test data is larger than max read size
 
387
        self.assertTrue(self.test_data_len > self.block_size)
 
388
 
 
389
        # retrieve data in blocks
 
390
        from_file = FakeReadFile(self.test_data)
 
391
        to_file = StringIO()
 
392
        pumpfile(from_file, to_file, self.test_data_len, self.block_size)
 
393
 
 
394
        # verify read size was equal to the maximum read size
 
395
        self.assertTrue(from_file.get_max_read_size() > 0)
 
396
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
 
397
        self.assertEqual(from_file.get_read_count(), 3)
 
398
 
 
399
        # report error if the data wasn't equal (we only report the size due
 
400
        # to the length of the data)
 
401
        response_data = to_file.getvalue()
 
402
        if response_data != self.test_data:
 
403
            message = "Data not equal.  Expected %d bytes, received %d."
 
404
            self.fail(message % (len(response_data), self.test_data_len))
 
405
 
 
406
    def test_to_eof(self):
 
407
        """Read to end-of-file and verify that the reads are not larger than
 
408
        the maximum read size."""
 
409
        # make sure test data is larger than max read size
 
410
        self.assertTrue(self.test_data_len > self.block_size)
 
411
 
 
412
        # retrieve data to EOF
 
413
        from_file = FakeReadFile(self.test_data)
 
414
        to_file = StringIO()
 
415
        pumpfile(from_file, to_file, -1, self.block_size)
 
416
 
 
417
        # verify read size was equal to the maximum read size
 
418
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
 
419
        self.assertEqual(from_file.get_read_count(), 4)
 
420
 
 
421
        # report error if the data wasn't equal (we only report the size due
 
422
        # to the length of the data)
 
423
        response_data = to_file.getvalue()
 
424
        if response_data != self.test_data:
 
425
            message = "Data not equal.  Expected %d bytes, received %d."
 
426
            self.fail(message % (len(response_data), self.test_data_len))
 
427
 
 
428
    def test_defaults(self):
 
429
        """Verifies that the default arguments will read to EOF -- this
 
430
        test verifies that any existing usages of pumpfile will not be broken
 
431
        with this new version."""
 
432
        # retrieve data using default (old) pumpfile method
 
433
        from_file = FakeReadFile(self.test_data)
 
434
        to_file = StringIO()
 
435
        pumpfile(from_file, to_file)
 
436
 
 
437
        # report error if the data wasn't equal (we only report the size due
 
438
        # to the length of the data)
 
439
        response_data = to_file.getvalue()
 
440
        if response_data != self.test_data:
 
441
            message = "Data not equal.  Expected %d bytes, received %d."
 
442
            self.fail(message % (len(response_data), self.test_data_len))
130
443
 
131
444
class TestSafeUnicode(TestCase):
132
445
 
148
461
                          '\xbb\xbb')
149
462
 
150
463
 
 
464
class TestSafeUtf8(TestCase):
 
465
 
 
466
    def test_from_ascii_string(self):
 
467
        f = 'foobar'
 
468
        self.assertEqual('foobar', osutils.safe_utf8(f))
 
469
 
 
470
    def test_from_unicode_string_ascii_contents(self):
 
471
        self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
 
472
 
 
473
    def test_from_unicode_string_unicode_contents(self):
 
474
        self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
 
475
 
 
476
    def test_from_utf8_string(self):
 
477
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
 
478
 
 
479
    def test_bad_utf8_string(self):
 
480
        self.assertRaises(BzrBadParameterNotUnicode,
 
481
                          osutils.safe_utf8, '\xbb\xbb')
 
482
 
 
483
 
 
484
class TestSafeRevisionId(TestCase):
 
485
 
 
486
    def test_from_ascii_string(self):
 
487
        # this shouldn't give a warning because it's getting an ascii string
 
488
        self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
 
489
 
 
490
    def test_from_unicode_string_ascii_contents(self):
 
491
        self.assertEqual('bargam',
 
492
                         osutils.safe_revision_id(u'bargam', warn=False))
 
493
 
 
494
    def test_from_unicode_deprecated(self):
 
495
        self.assertEqual('bargam',
 
496
            self.callDeprecated([osutils._revision_id_warning],
 
497
                                osutils.safe_revision_id, u'bargam'))
 
498
 
 
499
    def test_from_unicode_string_unicode_contents(self):
 
500
        self.assertEqual('bargam\xc2\xae',
 
501
                         osutils.safe_revision_id(u'bargam\xae', warn=False))
 
502
 
 
503
    def test_from_utf8_string(self):
 
504
        self.assertEqual('foo\xc2\xae',
 
505
                         osutils.safe_revision_id('foo\xc2\xae'))
 
506
 
 
507
    def test_none(self):
 
508
        """Currently, None is a valid revision_id"""
 
509
        self.assertEqual(None, osutils.safe_revision_id(None))
 
510
 
 
511
 
 
512
class TestSafeFileId(TestCase):
 
513
 
 
514
    def test_from_ascii_string(self):
 
515
        self.assertEqual('foobar', osutils.safe_file_id('foobar'))
 
516
 
 
517
    def test_from_unicode_string_ascii_contents(self):
 
518
        self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
 
519
 
 
520
    def test_from_unicode_deprecated(self):
 
521
        self.assertEqual('bargam',
 
522
            self.callDeprecated([osutils._file_id_warning],
 
523
                                osutils.safe_file_id, u'bargam'))
 
524
 
 
525
    def test_from_unicode_string_unicode_contents(self):
 
526
        self.assertEqual('bargam\xc2\xae',
 
527
                         osutils.safe_file_id(u'bargam\xae', warn=False))
 
528
 
 
529
    def test_from_utf8_string(self):
 
530
        self.assertEqual('foo\xc2\xae',
 
531
                         osutils.safe_file_id('foo\xc2\xae'))
 
532
 
 
533
    def test_none(self):
 
534
        """Currently, None is a valid revision_id"""
 
535
        self.assertEqual(None, osutils.safe_file_id(None))
 
536
 
 
537
 
151
538
class TestWin32Funcs(TestCase):
152
539
    """Test that the _win32 versions of os utilities return appropriate paths."""
153
540
 
154
541
    def test_abspath(self):
155
542
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
156
543
        self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
 
544
        self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
 
545
        self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
157
546
 
158
547
    def test_realpath(self):
159
548
        self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
172
561
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
173
562
 
174
563
    def test_getcwd(self):
175
 
        self.assertEqual(os.getcwdu().replace('\\', '/'), osutils._win32_getcwd())
 
564
        cwd = osutils._win32_getcwd()
 
565
        os_cwd = os.getcwdu()
 
566
        self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
 
567
        # win32 is inconsistent whether it returns lower or upper case
 
568
        # and even if it was consistent the user might type the other
 
569
        # so we force it to uppercase
 
570
        # running python.exe under cmd.exe return capital C:\\
 
571
        # running win32 python inside a cygwin shell returns lowercase
 
572
        self.assertEqual(os_cwd[0].upper(), cwd[0])
 
573
 
 
574
    def test_fixdrive(self):
 
575
        self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
 
576
        self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
 
577
        self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
 
578
 
 
579
    def test_win98_abspath(self):
 
580
        # absolute path
 
581
        self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
 
582
        self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
 
583
        # UNC path
 
584
        self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
 
585
        self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
 
586
        # relative path
 
587
        cwd = osutils.getcwd().rstrip('/')
 
588
        drive = osutils._nt_splitdrive(cwd)[0]
 
589
        self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
 
590
        self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
 
591
        # unicode path
 
592
        u = u'\u1234'
 
593
        self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
176
594
 
177
595
 
178
596
class TestWin32FuncsDirs(TestCaseInTempDir):
179
597
    """Test win32 functions that create files."""
180
598
    
181
599
    def test_getcwd(self):
 
600
        if win32utils.winver == 'Windows 98':
 
601
            raise TestSkipped('Windows 98 cannot handle unicode filenames')
182
602
        # Make sure getcwd can handle unicode filenames
183
603
        try:
184
 
            os.mkdir(u'B\xe5gfors')
 
604
            os.mkdir(u'mu-\xb5')
185
605
        except UnicodeError:
186
606
            raise TestSkipped("Unable to create Unicode filename")
187
607
 
188
 
        os.chdir(u'B\xe5gfors')
 
608
        os.chdir(u'mu-\xb5')
189
609
        # TODO: jam 20060427 This will probably fail on Mac OSX because
190
610
        #       it will change the normalization of B\xe5gfors
191
611
        #       Consider using a different unicode character, or make
192
612
        #       osutils.getcwd() renormalize the path.
193
 
        self.assertTrue(osutils._win32_getcwd().endswith(u'/B\xe5gfors'))
 
613
        self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
 
614
 
 
615
    def test_minimum_path_selection(self):
 
616
        self.assertEqual(set(),
 
617
            osutils.minimum_path_selection([]))
 
618
        self.assertEqual(set(['a', 'b']),
 
619
            osutils.minimum_path_selection(['a', 'b']))
 
620
        self.assertEqual(set(['a/', 'b']),
 
621
            osutils.minimum_path_selection(['a/', 'b']))
 
622
        self.assertEqual(set(['a/', 'b']),
 
623
            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
194
624
 
195
625
    def test_mkdtemp(self):
196
626
        tmpdir = osutils._win32_mkdtemp(dir='.')
209
639
        self.failIfExists('b')
210
640
        self.assertFileEqual('baz\n', 'a')
211
641
 
 
642
    def test_rename_missing_file(self):
 
643
        a = open('a', 'wb')
 
644
        a.write('foo\n')
 
645
        a.close()
 
646
 
 
647
        try:
 
648
            osutils._win32_rename('b', 'a')
 
649
        except (IOError, OSError), e:
 
650
            self.assertEqual(errno.ENOENT, e.errno)
 
651
        self.assertFileEqual('foo\n', 'a')
 
652
 
 
653
    def test_rename_missing_dir(self):
 
654
        os.mkdir('a')
 
655
        try:
 
656
            osutils._win32_rename('b', 'a')
 
657
        except (IOError, OSError), e:
 
658
            self.assertEqual(errno.ENOENT, e.errno)
 
659
 
 
660
    def test_rename_current_dir(self):
 
661
        os.mkdir('a')
 
662
        os.chdir('a')
 
663
        # You can't rename the working directory
 
664
        # doing rename non-existant . usually
 
665
        # just raises ENOENT, since non-existant
 
666
        # doesn't exist.
 
667
        try:
 
668
            osutils._win32_rename('b', '.')
 
669
        except (IOError, OSError), e:
 
670
            self.assertEqual(errno.ENOENT, e.errno)
 
671
 
 
672
    def test_splitpath(self):
 
673
        def check(expected, path):
 
674
            self.assertEqual(expected, osutils.splitpath(path))
 
675
 
 
676
        check(['a'], 'a')
 
677
        check(['a', 'b'], 'a/b')
 
678
        check(['a', 'b'], 'a/./b')
 
679
        check(['a', '.b'], 'a/.b')
 
680
        check(['a', '.b'], 'a\\.b')
 
681
 
 
682
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
 
683
 
 
684
 
 
685
class TestMacFuncsDirs(TestCaseInTempDir):
 
686
    """Test mac special functions that require directories."""
 
687
 
 
688
    def test_getcwd(self):
 
689
        # On Mac, this will actually create Ba\u030agfors
 
690
        # but chdir will still work, because it accepts both paths
 
691
        try:
 
692
            os.mkdir(u'B\xe5gfors')
 
693
        except UnicodeError:
 
694
            raise TestSkipped("Unable to create Unicode filename")
 
695
 
 
696
        os.chdir(u'B\xe5gfors')
 
697
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
 
698
 
 
699
    def test_getcwd_nonnorm(self):
 
700
        # Test that _mac_getcwd() will normalize this path
 
701
        try:
 
702
            os.mkdir(u'Ba\u030agfors')
 
703
        except UnicodeError:
 
704
            raise TestSkipped("Unable to create Unicode filename")
 
705
 
 
706
        os.chdir(u'Ba\u030agfors')
 
707
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
 
708
 
212
709
 
213
710
class TestSplitLines(TestCase):
214
711
 
225
722
 
226
723
class TestWalkDirs(TestCaseInTempDir):
227
724
 
228
 
    def test_walkdirs(self):
229
 
        tree = [
230
 
            '.bzr',
231
 
            '0file',
232
 
            '1dir/',
233
 
            '1dir/0file',
234
 
            '1dir/1dir/',
235
 
            '2file'
236
 
            ]
237
 
        self.build_tree(tree)
238
 
        expected_dirblocks = [
239
 
                [
240
 
                    ('0file', '0file', 'file'),
241
 
                    ('1dir', '1dir', 'directory'),
242
 
                    ('2file', '2file', 'file'),
243
 
                ],
244
 
                [
245
 
                    ('1dir/0file', '0file', 'file'),
246
 
                    ('1dir/1dir', '1dir', 'directory'),
247
 
                ],
248
 
                [
249
 
                ],
250
 
            ]
251
 
        result = []
252
 
        found_bzrdir = False
253
 
        for dirblock in osutils.walkdirs('.'):
254
 
            if len(dirblock) and dirblock[0][1] == '.bzr':
255
 
                # this tests the filtering of selected paths
256
 
                found_bzrdir = True
257
 
                del dirblock[0]
258
 
            result.append(dirblock)
259
 
 
260
 
        self.assertTrue(found_bzrdir)
261
 
        self.assertEqual(expected_dirblocks,
262
 
            [[line[0:3] for line in block] for block in result])
263
 
 
264
725
    def test_readdir(self):
265
726
        tree = [
266
727
            '.bzr/',
281
742
        expected = zip(expected_names, expected_kind)
282
743
        self.assertEqual(expected, sorted(read_result))
283
744
        
 
745
    def test_walkdirs(self):
 
746
        tree = [
 
747
            '.bzr',
 
748
            '0file',
 
749
            '1dir/',
 
750
            '1dir/0file',
 
751
            '1dir/1dir/',
 
752
            '2file'
 
753
            ]
 
754
        self.build_tree(tree)
 
755
        expected_dirblocks = [
 
756
                (('', '.'),
 
757
                 [('0file', '0file', 'file'),
 
758
                  ('1dir', '1dir', 'directory'),
 
759
                  ('2file', '2file', 'file'),
 
760
                 ]
 
761
                ),
 
762
                (('1dir', './1dir'),
 
763
                 [('1dir/0file', '0file', 'file'),
 
764
                  ('1dir/1dir', '1dir', 'directory'),
 
765
                 ]
 
766
                ),
 
767
                (('1dir/1dir', './1dir/1dir'),
 
768
                 [
 
769
                 ]
 
770
                ),
 
771
            ]
 
772
        result = []
 
773
        found_bzrdir = False
 
774
        for dirdetail, dirblock in osutils.walkdirs('.'):
 
775
            if len(dirblock) and dirblock[0][1] == '.bzr':
 
776
                # this tests the filtering of selected paths
 
777
                found_bzrdir = True
 
778
                del dirblock[0]
 
779
            result.append((dirdetail, dirblock))
 
780
 
 
781
        self.assertTrue(found_bzrdir)
 
782
        self.assertEqual(expected_dirblocks,
 
783
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
784
        # you can search a subdir only, with a supplied prefix.
 
785
        result = []
 
786
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
 
787
            result.append(dirblock)
 
788
        self.assertEqual(expected_dirblocks[1:],
 
789
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
790
 
 
791
    def test__walkdirs_utf8(self):
 
792
        tree = [
 
793
            '.bzr',
 
794
            '0file',
 
795
            '1dir/',
 
796
            '1dir/0file',
 
797
            '1dir/1dir/',
 
798
            '2file'
 
799
            ]
 
800
        self.build_tree(tree)
 
801
        expected_dirblocks = [
 
802
                (('', '.'),
 
803
                 [('0file', '0file', 'file'),
 
804
                  ('1dir', '1dir', 'directory'),
 
805
                  ('2file', '2file', 'file'),
 
806
                 ]
 
807
                ),
 
808
                (('1dir', './1dir'),
 
809
                 [('1dir/0file', '0file', 'file'),
 
810
                  ('1dir/1dir', '1dir', 'directory'),
 
811
                 ]
 
812
                ),
 
813
                (('1dir/1dir', './1dir/1dir'),
 
814
                 [
 
815
                 ]
 
816
                ),
 
817
            ]
 
818
        result = []
 
819
        found_bzrdir = False
 
820
        for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
 
821
            if len(dirblock) and dirblock[0][1] == '.bzr':
 
822
                # this tests the filtering of selected paths
 
823
                found_bzrdir = True
 
824
                del dirblock[0]
 
825
            result.append((dirdetail, dirblock))
 
826
 
 
827
        self.assertTrue(found_bzrdir)
 
828
        self.assertEqual(expected_dirblocks,
 
829
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
830
        # you can search a subdir only, with a supplied prefix.
 
831
        result = []
 
832
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
 
833
            result.append(dirblock)
 
834
        self.assertEqual(expected_dirblocks[1:],
 
835
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
836
 
 
837
    def _filter_out_stat(self, result):
 
838
        """Filter out the stat value from the walkdirs result"""
 
839
        for dirdetail, dirblock in result:
 
840
            new_dirblock = []
 
841
            for info in dirblock:
 
842
                # Ignore info[3] which is the stat
 
843
                new_dirblock.append((info[0], info[1], info[2], info[4]))
 
844
            dirblock[:] = new_dirblock
 
845
 
 
846
    def test__walkdirs_utf8_selection(self):
 
847
        # Just trigger the function once, to make sure it has selected a real
 
848
        # implementation.
 
849
        list(osutils._walkdirs_utf8('.'))
 
850
        if WalkdirsWin32Feature.available():
 
851
            # If the compiled form is available, make sure it is used
 
852
            from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
853
            self.assertIs(_walkdirs_utf8_win32_find_file,
 
854
                          osutils._real_walkdirs_utf8)
 
855
        elif sys.platform == 'win32':
 
856
            self.assertIs(osutils._walkdirs_unicode_to_utf8,
 
857
                          osutils._real_walkdirs_utf8)
 
858
        elif osutils._fs_enc.upper() in ('UTF-8', 'ASCII', 'ANSI_X3.4-1968'): # ascii
 
859
            self.assertIs(osutils._walkdirs_fs_utf8,
 
860
                          osutils._real_walkdirs_utf8)
 
861
        else:
 
862
            self.assertIs(osutils._walkdirs_unicode_to_utf8,
 
863
                          osutils._real_walkdirs_utf8)
 
864
 
 
865
    def _save_platform_info(self):
 
866
        cur_winver = win32utils.winver
 
867
        cur_fs_enc = osutils._fs_enc
 
868
        cur_real_walkdirs_utf8 = osutils._real_walkdirs_utf8
 
869
        def restore():
 
870
            win32utils.winver = cur_winver
 
871
            osutils._fs_enc = cur_fs_enc
 
872
            osutils._real_walkdirs_utf8 = cur_real_walkdirs_utf8
 
873
        self.addCleanup(restore)
 
874
 
 
875
    def assertWalkdirsUtf8Is(self, expected):
 
876
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
 
877
        # Force it to redetect
 
878
        osutils._real_walkdirs_utf8 = None
 
879
        # Nothing to list, but should still trigger the selection logic
 
880
        self.assertEqual([(('', '.'), [])], list(osutils._walkdirs_utf8('.')))
 
881
        self.assertIs(expected, osutils._real_walkdirs_utf8)
 
882
 
 
883
    def test_force_walkdirs_utf8_fs_utf8(self):
 
884
        self._save_platform_info()
 
885
        win32utils.winver = None # Avoid the win32 detection code
 
886
        osutils._fs_enc = 'UTF-8'
 
887
        self.assertWalkdirsUtf8Is(osutils._walkdirs_fs_utf8)
 
888
 
 
889
    def test_force_walkdirs_utf8_fs_ascii(self):
 
890
        self._save_platform_info()
 
891
        win32utils.winver = None # Avoid the win32 detection code
 
892
        osutils._fs_enc = 'US-ASCII'
 
893
        self.assertWalkdirsUtf8Is(osutils._walkdirs_fs_utf8)
 
894
 
 
895
    def test_force_walkdirs_utf8_fs_ANSI(self):
 
896
        self._save_platform_info()
 
897
        win32utils.winver = None # Avoid the win32 detection code
 
898
        osutils._fs_enc = 'ANSI_X3.4-1968'
 
899
        self.assertWalkdirsUtf8Is(osutils._walkdirs_fs_utf8)
 
900
 
 
901
    def test_force_walkdirs_utf8_fs_latin1(self):
 
902
        self._save_platform_info()
 
903
        win32utils.winver = None # Avoid the win32 detection code
 
904
        osutils._fs_enc = 'latin1'
 
905
        self.assertWalkdirsUtf8Is(osutils._walkdirs_unicode_to_utf8)
 
906
 
 
907
    def test_force_walkdirs_utf8_nt(self):
 
908
        self.requireFeature(WalkdirsWin32Feature)
 
909
        self._save_platform_info()
 
910
        win32utils.winver = 'Windows NT'
 
911
        from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
912
        self.assertWalkdirsUtf8Is(_walkdirs_utf8_win32_find_file)
 
913
 
 
914
    def test_force_walkdirs_utf8_nt(self):
 
915
        self.requireFeature(WalkdirsWin32Feature)
 
916
        self._save_platform_info()
 
917
        win32utils.winver = 'Windows 98'
 
918
        self.assertWalkdirsUtf8Is(osutils._walkdirs_unicode_to_utf8)
 
919
 
 
920
    def test_unicode_walkdirs(self):
 
921
        """Walkdirs should always return unicode paths."""
 
922
        name0 = u'0file-\xb6'
 
923
        name1 = u'1dir-\u062c\u0648'
 
924
        name2 = u'2file-\u0633'
 
925
        tree = [
 
926
            name0,
 
927
            name1 + '/',
 
928
            name1 + '/' + name0,
 
929
            name1 + '/' + name1 + '/',
 
930
            name2,
 
931
            ]
 
932
        try:
 
933
            self.build_tree(tree)
 
934
        except UnicodeError:
 
935
            raise TestSkipped('Could not represent Unicode chars'
 
936
                              ' in current encoding.')
 
937
        expected_dirblocks = [
 
938
                ((u'', u'.'),
 
939
                 [(name0, name0, 'file', './' + name0),
 
940
                  (name1, name1, 'directory', './' + name1),
 
941
                  (name2, name2, 'file', './' + name2),
 
942
                 ]
 
943
                ),
 
944
                ((name1, './' + name1),
 
945
                 [(name1 + '/' + name0, name0, 'file', './' + name1
 
946
                                                        + '/' + name0),
 
947
                  (name1 + '/' + name1, name1, 'directory', './' + name1
 
948
                                                            + '/' + name1),
 
949
                 ]
 
950
                ),
 
951
                ((name1 + '/' + name1, './' + name1 + '/' + name1),
 
952
                 [
 
953
                 ]
 
954
                ),
 
955
            ]
 
956
        result = list(osutils.walkdirs('.'))
 
957
        self._filter_out_stat(result)
 
958
        self.assertEqual(expected_dirblocks, result)
 
959
        result = list(osutils.walkdirs(u'./'+name1, name1))
 
960
        self._filter_out_stat(result)
 
961
        self.assertEqual(expected_dirblocks[1:], result)
 
962
 
 
963
    def test_unicode__walkdirs_utf8(self):
 
964
        """Walkdirs_utf8 should always return utf8 paths.
 
965
 
 
966
        The abspath portion might be in unicode or utf-8
 
967
        """
 
968
        name0 = u'0file-\xb6'
 
969
        name1 = u'1dir-\u062c\u0648'
 
970
        name2 = u'2file-\u0633'
 
971
        tree = [
 
972
            name0,
 
973
            name1 + '/',
 
974
            name1 + '/' + name0,
 
975
            name1 + '/' + name1 + '/',
 
976
            name2,
 
977
            ]
 
978
        try:
 
979
            self.build_tree(tree)
 
980
        except UnicodeError:
 
981
            raise TestSkipped('Could not represent Unicode chars'
 
982
                              ' in current encoding.')
 
983
        name0 = name0.encode('utf8')
 
984
        name1 = name1.encode('utf8')
 
985
        name2 = name2.encode('utf8')
 
986
 
 
987
        expected_dirblocks = [
 
988
                (('', '.'),
 
989
                 [(name0, name0, 'file', './' + name0),
 
990
                  (name1, name1, 'directory', './' + name1),
 
991
                  (name2, name2, 'file', './' + name2),
 
992
                 ]
 
993
                ),
 
994
                ((name1, './' + name1),
 
995
                 [(name1 + '/' + name0, name0, 'file', './' + name1
 
996
                                                        + '/' + name0),
 
997
                  (name1 + '/' + name1, name1, 'directory', './' + name1
 
998
                                                            + '/' + name1),
 
999
                 ]
 
1000
                ),
 
1001
                ((name1 + '/' + name1, './' + name1 + '/' + name1),
 
1002
                 [
 
1003
                 ]
 
1004
                ),
 
1005
            ]
 
1006
        result = []
 
1007
        # For ease in testing, if walkdirs_utf8 returns Unicode, assert that
 
1008
        # all abspaths are Unicode, and encode them back into utf8.
 
1009
        for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
 
1010
            self.assertIsInstance(dirdetail[0], str)
 
1011
            if isinstance(dirdetail[1], unicode):
 
1012
                dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
 
1013
                dirblock = [list(info) for info in dirblock]
 
1014
                for info in dirblock:
 
1015
                    self.assertIsInstance(info[4], unicode)
 
1016
                    info[4] = info[4].encode('utf8')
 
1017
            new_dirblock = []
 
1018
            for info in dirblock:
 
1019
                self.assertIsInstance(info[0], str)
 
1020
                self.assertIsInstance(info[1], str)
 
1021
                self.assertIsInstance(info[4], str)
 
1022
                # Remove the stat information
 
1023
                new_dirblock.append((info[0], info[1], info[2], info[4]))
 
1024
            result.append((dirdetail, new_dirblock))
 
1025
        self.assertEqual(expected_dirblocks, result)
 
1026
 
 
1027
    def test_unicode__walkdirs_unicode_to_utf8(self):
 
1028
        """walkdirs_unicode_to_utf8 should be a safe fallback everywhere
 
1029
 
 
1030
        The abspath portion should be in unicode
 
1031
        """
 
1032
        name0u = u'0file-\xb6'
 
1033
        name1u = u'1dir-\u062c\u0648'
 
1034
        name2u = u'2file-\u0633'
 
1035
        tree = [
 
1036
            name0u,
 
1037
            name1u + '/',
 
1038
            name1u + '/' + name0u,
 
1039
            name1u + '/' + name1u + '/',
 
1040
            name2u,
 
1041
            ]
 
1042
        try:
 
1043
            self.build_tree(tree)
 
1044
        except UnicodeError:
 
1045
            raise TestSkipped('Could not represent Unicode chars'
 
1046
                              ' in current encoding.')
 
1047
        name0 = name0u.encode('utf8')
 
1048
        name1 = name1u.encode('utf8')
 
1049
        name2 = name2u.encode('utf8')
 
1050
 
 
1051
        # All of the abspaths should be in unicode, all of the relative paths
 
1052
        # should be in utf8
 
1053
        expected_dirblocks = [
 
1054
                (('', '.'),
 
1055
                 [(name0, name0, 'file', './' + name0u),
 
1056
                  (name1, name1, 'directory', './' + name1u),
 
1057
                  (name2, name2, 'file', './' + name2u),
 
1058
                 ]
 
1059
                ),
 
1060
                ((name1, './' + name1u),
 
1061
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1062
                                                        + '/' + name0u),
 
1063
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1064
                                                            + '/' + name1u),
 
1065
                 ]
 
1066
                ),
 
1067
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1068
                 [
 
1069
                 ]
 
1070
                ),
 
1071
            ]
 
1072
        result = list(osutils._walkdirs_unicode_to_utf8('.'))
 
1073
        self._filter_out_stat(result)
 
1074
        self.assertEqual(expected_dirblocks, result)
 
1075
 
 
1076
    def test__walkdirs_utf_win32_find_file(self):
 
1077
        self.requireFeature(WalkdirsWin32Feature)
 
1078
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1079
        from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
1080
        name0u = u'0file-\xb6'
 
1081
        name1u = u'1dir-\u062c\u0648'
 
1082
        name2u = u'2file-\u0633'
 
1083
        tree = [
 
1084
            name0u,
 
1085
            name1u + '/',
 
1086
            name1u + '/' + name0u,
 
1087
            name1u + '/' + name1u + '/',
 
1088
            name2u,
 
1089
            ]
 
1090
        self.build_tree(tree)
 
1091
        name0 = name0u.encode('utf8')
 
1092
        name1 = name1u.encode('utf8')
 
1093
        name2 = name2u.encode('utf8')
 
1094
 
 
1095
        # All of the abspaths should be in unicode, all of the relative paths
 
1096
        # should be in utf8
 
1097
        expected_dirblocks = [
 
1098
                (('', '.'),
 
1099
                 [(name0, name0, 'file', './' + name0u),
 
1100
                  (name1, name1, 'directory', './' + name1u),
 
1101
                  (name2, name2, 'file', './' + name2u),
 
1102
                 ]
 
1103
                ),
 
1104
                ((name1, './' + name1u),
 
1105
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1106
                                                        + '/' + name0u),
 
1107
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1108
                                                            + '/' + name1u),
 
1109
                 ]
 
1110
                ),
 
1111
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1112
                 [
 
1113
                 ]
 
1114
                ),
 
1115
            ]
 
1116
        result = list(_walkdirs_utf8_win32_find_file(u'.'))
 
1117
        self._filter_out_stat(result)
 
1118
        self.assertEqual(expected_dirblocks, result)
 
1119
 
 
1120
    def assertStatIsCorrect(self, path, win32stat):
 
1121
        os_stat = os.stat(path)
 
1122
        self.assertEqual(os_stat.st_size, win32stat.st_size)
 
1123
        self.assertAlmostEqual(os_stat.st_mtime, win32stat.st_mtime, places=4)
 
1124
        self.assertAlmostEqual(os_stat.st_ctime, win32stat.st_ctime, places=4)
 
1125
        self.assertAlmostEqual(os_stat.st_atime, win32stat.st_atime, places=4)
 
1126
        self.assertEqual(os_stat.st_dev, win32stat.st_dev)
 
1127
        self.assertEqual(os_stat.st_ino, win32stat.st_ino)
 
1128
        self.assertEqual(os_stat.st_mode, win32stat.st_mode)
 
1129
 
 
1130
    def test__walkdirs_utf_win32_find_file_stat_file(self):
 
1131
        """make sure our Stat values are valid"""
 
1132
        self.requireFeature(WalkdirsWin32Feature)
 
1133
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1134
        from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
1135
        name0u = u'0file-\xb6'
 
1136
        name0 = name0u.encode('utf8')
 
1137
        self.build_tree([name0u])
 
1138
        # I hate to sleep() here, but I'm trying to make the ctime different
 
1139
        # from the mtime
 
1140
        time.sleep(2)
 
1141
        f = open(name0u, 'ab')
 
1142
        try:
 
1143
            f.write('just a small update')
 
1144
        finally:
 
1145
            f.close()
 
1146
 
 
1147
        result = list(_walkdirs_utf8_win32_find_file(u'.'))
 
1148
        entry = result[0][1][0]
 
1149
        self.assertEqual((name0, name0, 'file'), entry[:3])
 
1150
        self.assertEqual(u'./' + name0u, entry[4])
 
1151
        self.assertStatIsCorrect(entry[4], entry[3])
 
1152
        self.assertNotEqual(entry[3].st_mtime, entry[3].st_ctime)
 
1153
 
 
1154
    def test__walkdirs_utf_win32_find_file_stat_directory(self):
 
1155
        """make sure our Stat values are valid"""
 
1156
        self.requireFeature(WalkdirsWin32Feature)
 
1157
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1158
        from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file
 
1159
        name0u = u'0dir-\u062c\u0648'
 
1160
        name0 = name0u.encode('utf8')
 
1161
        self.build_tree([name0u + '/'])
 
1162
 
 
1163
        result = list(_walkdirs_utf8_win32_find_file(u'.'))
 
1164
        entry = result[0][1][0]
 
1165
        self.assertEqual((name0, name0, 'directory'), entry[:3])
 
1166
        self.assertEqual(u'./' + name0u, entry[4])
 
1167
        self.assertStatIsCorrect(entry[4], entry[3])
 
1168
 
 
1169
    def assertPathCompare(self, path_less, path_greater):
 
1170
        """check that path_less and path_greater compare correctly."""
 
1171
        self.assertEqual(0, osutils.compare_paths_prefix_order(
 
1172
            path_less, path_less))
 
1173
        self.assertEqual(0, osutils.compare_paths_prefix_order(
 
1174
            path_greater, path_greater))
 
1175
        self.assertEqual(-1, osutils.compare_paths_prefix_order(
 
1176
            path_less, path_greater))
 
1177
        self.assertEqual(1, osutils.compare_paths_prefix_order(
 
1178
            path_greater, path_less))
 
1179
 
 
1180
    def test_compare_paths_prefix_order(self):
 
1181
        # root before all else
 
1182
        self.assertPathCompare("/", "/a")
 
1183
        # alpha within a dir
 
1184
        self.assertPathCompare("/a", "/b")
 
1185
        self.assertPathCompare("/b", "/z")
 
1186
        # high dirs before lower.
 
1187
        self.assertPathCompare("/z", "/a/a")
 
1188
        # except if the deeper dir should be output first
 
1189
        self.assertPathCompare("/a/b/c", "/d/g")
 
1190
        # lexical betwen dirs of the same height
 
1191
        self.assertPathCompare("/a/z", "/z/z")
 
1192
        self.assertPathCompare("/a/c/z", "/a/d/e")
 
1193
 
 
1194
        # this should also be consistent for no leading / paths
 
1195
        # root before all else
 
1196
        self.assertPathCompare("", "a")
 
1197
        # alpha within a dir
 
1198
        self.assertPathCompare("a", "b")
 
1199
        self.assertPathCompare("b", "z")
 
1200
        # high dirs before lower.
 
1201
        self.assertPathCompare("z", "a/a")
 
1202
        # except if the deeper dir should be output first
 
1203
        self.assertPathCompare("a/b/c", "d/g")
 
1204
        # lexical betwen dirs of the same height
 
1205
        self.assertPathCompare("a/z", "z/z")
 
1206
        self.assertPathCompare("a/c/z", "a/d/e")
 
1207
 
 
1208
    def test_path_prefix_sorting(self):
 
1209
        """Doing a sort on path prefix should match our sample data."""
 
1210
        original_paths = [
 
1211
            'a',
 
1212
            'a/b',
 
1213
            'a/b/c',
 
1214
            'b',
 
1215
            'b/c',
 
1216
            'd',
 
1217
            'd/e',
 
1218
            'd/e/f',
 
1219
            'd/f',
 
1220
            'd/g',
 
1221
            'g',
 
1222
            ]
 
1223
 
 
1224
        dir_sorted_paths = [
 
1225
            'a',
 
1226
            'b',
 
1227
            'd',
 
1228
            'g',
 
1229
            'a/b',
 
1230
            'a/b/c',
 
1231
            'b/c',
 
1232
            'd/e',
 
1233
            'd/f',
 
1234
            'd/g',
 
1235
            'd/e/f',
 
1236
            ]
 
1237
 
 
1238
        self.assertEqual(
 
1239
            dir_sorted_paths,
 
1240
            sorted(original_paths, key=osutils.path_prefix_key))
 
1241
        # using the comparison routine shoudl work too:
 
1242
        self.assertEqual(
 
1243
            dir_sorted_paths,
 
1244
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
 
1245
 
 
1246
 
 
1247
class TestCopyTree(TestCaseInTempDir):
 
1248
    
 
1249
    def test_copy_basic_tree(self):
 
1250
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
1251
        osutils.copy_tree('source', 'target')
 
1252
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
 
1253
        self.assertEqual(['c'], os.listdir('target/b'))
 
1254
 
 
1255
    def test_copy_tree_target_exists(self):
 
1256
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
 
1257
                         'target/'])
 
1258
        osutils.copy_tree('source', 'target')
 
1259
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
 
1260
        self.assertEqual(['c'], os.listdir('target/b'))
 
1261
 
 
1262
    def test_copy_tree_symlinks(self):
 
1263
        self.requireFeature(SymlinkFeature)
 
1264
        self.build_tree(['source/'])
 
1265
        os.symlink('a/generic/path', 'source/lnk')
 
1266
        osutils.copy_tree('source', 'target')
 
1267
        self.assertEqual(['lnk'], os.listdir('target'))
 
1268
        self.assertEqual('a/generic/path', os.readlink('target/lnk'))
 
1269
 
 
1270
    def test_copy_tree_handlers(self):
 
1271
        processed_files = []
 
1272
        processed_links = []
 
1273
        def file_handler(from_path, to_path):
 
1274
            processed_files.append(('f', from_path, to_path))
 
1275
        def dir_handler(from_path, to_path):
 
1276
            processed_files.append(('d', from_path, to_path))
 
1277
        def link_handler(from_path, to_path):
 
1278
            processed_links.append((from_path, to_path))
 
1279
        handlers = {'file':file_handler,
 
1280
                    'directory':dir_handler,
 
1281
                    'symlink':link_handler,
 
1282
                   }
 
1283
 
 
1284
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
1285
        if osutils.has_symlinks():
 
1286
            os.symlink('a/generic/path', 'source/lnk')
 
1287
        osutils.copy_tree('source', 'target', handlers=handlers)
 
1288
 
 
1289
        self.assertEqual([('d', 'source', 'target'),
 
1290
                          ('f', 'source/a', 'target/a'),
 
1291
                          ('d', 'source/b', 'target/b'),
 
1292
                          ('f', 'source/b/c', 'target/b/c'),
 
1293
                         ], processed_files)
 
1294
        self.failIfExists('target')
 
1295
        if osutils.has_symlinks():
 
1296
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
 
1297
 
 
1298
 
 
1299
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
 
1300
# [bialix] 2006/12/26
 
1301
 
 
1302
 
 
1303
class TestSetUnsetEnv(TestCase):
 
1304
    """Test updating the environment"""
 
1305
 
 
1306
    def setUp(self):
 
1307
        super(TestSetUnsetEnv, self).setUp()
 
1308
 
 
1309
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
 
1310
                         'Environment was not cleaned up properly.'
 
1311
                         ' Variable BZR_TEST_ENV_VAR should not exist.')
 
1312
        def cleanup():
 
1313
            if 'BZR_TEST_ENV_VAR' in os.environ:
 
1314
                del os.environ['BZR_TEST_ENV_VAR']
 
1315
 
 
1316
        self.addCleanup(cleanup)
 
1317
 
 
1318
    def test_set(self):
 
1319
        """Test that we can set an env variable"""
 
1320
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
1321
        self.assertEqual(None, old)
 
1322
        self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
 
1323
 
 
1324
    def test_double_set(self):
 
1325
        """Test that we get the old value out"""
 
1326
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
1327
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
 
1328
        self.assertEqual('foo', old)
 
1329
        self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
 
1330
 
 
1331
    def test_unicode(self):
 
1332
        """Environment can only contain plain strings
 
1333
        
 
1334
        So Unicode strings must be encoded.
 
1335
        """
 
1336
        uni_val, env_val = probe_unicode_in_user_encoding()
 
1337
        if uni_val is None:
 
1338
            raise TestSkipped('Cannot find a unicode character that works in'
 
1339
                              ' encoding %s' % (bzrlib.user_encoding,))
 
1340
 
 
1341
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
 
1342
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
 
1343
 
 
1344
    def test_unset(self):
 
1345
        """Test that passing None will remove the env var"""
 
1346
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
1347
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
 
1348
        self.assertEqual('foo', old)
 
1349
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
 
1350
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
 
1351
 
 
1352
 
 
1353
class TestLocalTimeOffset(TestCase):
 
1354
 
 
1355
    def test_local_time_offset(self):
 
1356
        """Test that local_time_offset() returns a sane value."""
 
1357
        offset = osutils.local_time_offset()
 
1358
        self.assertTrue(isinstance(offset, int))
 
1359
        # Test that the offset is no more than a eighteen hours in
 
1360
        # either direction.
 
1361
        # Time zone handling is system specific, so it is difficult to
 
1362
        # do more specific tests, but a value outside of this range is
 
1363
        # probably wrong.
 
1364
        eighteen_hours = 18 * 3600
 
1365
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
1366
 
 
1367
    def test_local_time_offset_with_timestamp(self):
 
1368
        """Test that local_time_offset() works with a timestamp."""
 
1369
        offset = osutils.local_time_offset(1000000000.1234567)
 
1370
        self.assertTrue(isinstance(offset, int))
 
1371
        eighteen_hours = 18 * 3600
 
1372
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
1373
 
 
1374
 
 
1375
class TestShaFileByName(TestCaseInTempDir):
 
1376
 
 
1377
    def test_sha_empty(self):
 
1378
        self.build_tree_contents([('foo', '')])
 
1379
        expected_sha = osutils.sha_string('')
 
1380
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
 
1381
 
 
1382
    def test_sha_mixed_endings(self):
 
1383
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
 
1384
        self.build_tree_contents([('foo', text)])
 
1385
        expected_sha = osutils.sha_string(text)
 
1386
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
 
1387
 
 
1388
 
 
1389
_debug_text = \
 
1390
r'''# Copyright (C) 2005, 2006 Canonical Ltd
 
1391
#
 
1392
# This program is free software; you can redistribute it and/or modify
 
1393
# it under the terms of the GNU General Public License as published by
 
1394
# the Free Software Foundation; either version 2 of the License, or
 
1395
# (at your option) any later version.
 
1396
#
 
1397
# This program is distributed in the hope that it will be useful,
 
1398
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
1399
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
1400
# GNU General Public License for more details.
 
1401
#
 
1402
# You should have received a copy of the GNU General Public License
 
1403
# along with this program; if not, write to the Free Software
 
1404
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
1405
 
 
1406
 
 
1407
# NOTE: If update these, please also update the help for global-options in
 
1408
#       bzrlib/help_topics/__init__.py
 
1409
 
 
1410
debug_flags = set()
 
1411
"""Set of flags that enable different debug behaviour.
 
1412
 
 
1413
These are set with eg ``-Dlock`` on the bzr command line.
 
1414
 
 
1415
Options include:
 
1416
 
 
1417
 * auth - show authentication sections used
 
1418
 * error - show stack traces for all top level exceptions
 
1419
 * evil - capture call sites that do expensive or badly-scaling operations.
 
1420
 * fetch - trace history copying between repositories
 
1421
 * graph - trace graph traversal information
 
1422
 * hashcache - log every time a working file is read to determine its hash
 
1423
 * hooks - trace hook execution
 
1424
 * hpss - trace smart protocol requests and responses
 
1425
 * http - trace http connections, requests and responses
 
1426
 * index - trace major index operations
 
1427
 * knit - trace knit operations
 
1428
 * lock - trace when lockdir locks are taken or released
 
1429
 * merge - emit information for debugging merges
 
1430
 * pack - emit information about pack operations
 
1431
 
 
1432
"""
 
1433
'''
 
1434
 
 
1435
 
 
1436
class TestResourceLoading(TestCaseInTempDir):
 
1437
 
 
1438
    def test_resource_string(self):
 
1439
        # test resource in bzrlib
 
1440
        text = osutils.resource_string('bzrlib', 'debug.py')
 
1441
        self.assertEquals(_debug_text, text)
 
1442
        # test resource under bzrlib
 
1443
        text = osutils.resource_string('bzrlib.ui', 'text.py')
 
1444
        self.assertContainsRe(text, "class TextUIFactory")
 
1445
        # test unsupported package
 
1446
        self.assertRaises(errors.BzrError, osutils.resource_string, 'zzzz',
 
1447
            'yyy.xx')
 
1448
        # test unknown resource
 
1449
        self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')