# Copyright (C) 2010, 2011 Lars Wirzenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import stat import unittest import summainlib class FakeChecksummer(object): def update(self, data): pass def hexdigest(self): return 'abc' class FakeOpenFile(object): def __call__(self, filename): self.data = 'some data' return self def read(self, amount): data = self.data[:amount] self.data = self.data[len(data):] return data def close(self): pass def __enter__(self): return self def __exit__(self, a, b, c): pass class FakeReadlink(object): def __init__(self, parent): self.parent = parent def __call__(self, filename): if stat.S_ISLNK(self.parent.st[summainlib.RESULT_MODE]): self.target = 'symlink' else: self.target = '' return self.target class FilesystemObjectTests(unittest.TestCase): def setUp(self): self.st = { summainlib.RESULT_MTIME_SEC: 1262307723, summainlib.RESULT_MTIME_NSEC: 123456789, summainlib.RESULT_MODE: stat.S_IFREG | 0644, summainlib.RESULT_INO: 12765, summainlib.RESULT_DEV: 42, summainlib.RESULT_NLINK: 2, summainlib.RESULT_SIZE: 1, summainlib.RESULT_UID: 0, summainlib.RESULT_GID: 0 } self.nn = summainlib.NumberNormalizer() self.pn = summainlib.SamePath() self.exclude = [] def new(self, name, mode=None): if mode is not None: self.st[summainlib.RESULT_MODE] = mode return summainlib.FilesystemObject( name, self.nn, self.pn, self.exclude, stat_result=self.st, sha1=FakeChecksummer(), sha224=FakeChecksummer(), sha256=FakeChecksummer(), sha384=FakeChecksummer(), sha512=FakeChecksummer(), md5=FakeChecksummer(), open_file=FakeOpenFile(), readlink=FakeReadlink(self), xattrs={}) def test_raises_keyerror_for_unknown_field(self): self.assertRaises(KeyError, self.new('foo').__getitem__, 'UNKNOWNHASH') def test_formats_simple_name_identically(self): self.assertEqual(self.new('foo')['Name'], 'foo') def test_formats_space_correctly(self): self.assertEqual(self.new('foo bar')['Name'], 'foo%20bar') def test_formats_mtime_correctly(self): self.assertEqual(self.new('foo')['Mtime'], '2010-01-01 01:02:03.123456789 +0000') def test_formats_mode_for_regular_file_correctly(self): self.assertEqual(self.new('foo')['Mode'], '100644') def test_formats_inode_number_correctly(self): # Note: normalization makes the result be 1. self.assertEqual(self.new('foo')['Ino'], '1') def test_formats_device_number_correctly(self): # Note: normalization makes the result be 1. self.assertEqual(self.new('foo')['Dev'], '1') def test_formats_link_count_correctly(self): self.assertEqual(self.new('foo')['Nlink'], '2') def test_formats_size_correctly(self): self.assertEqual(self.new('foo')['Size'], '1') def test_formats_uid_correctly(self): self.assertEqual(self.new('foo')['Uid'], '0') def test_formats_username_correctly(self): self.assertEqual(self.new('foo')['Username'], 'root') def test_formats_gid_correctly(self): self.assertEqual(self.new('foo')['Gid'], '0') def test_formats_group_correctly(self): self.assertEqual(self.new('foo')['Group'], 'root') def test_formats_checksums_correctly_for_regular_file(self): self.assertEqual(self.new('foo')['MD5'], 'abc') self.assertEqual(self.new('foo')['SHA1'], 'abc') self.assertEqual(self.new('foo')['SHA224'], 'abc') self.assertEqual(self.new('foo')['SHA256'], 'abc') self.assertEqual(self.new('foo')['SHA384'], 'abc') self.assertEqual(self.new('foo')['SHA512'], 'abc') def test_formats_checksums_correctly_for_special_file(self): self.st[summainlib.RESULT_MODE] = stat.S_IFDIR | 0755 self.assertEqual(self.new('foo')['MD5'], '') self.assertEqual(self.new('foo')['SHA1'], '') self.assertEqual(self.new('foo')['SHA224'], '') self.assertEqual(self.new('foo')['SHA256'], '') self.assertEqual(self.new('foo')['SHA384'], '') self.assertEqual(self.new('foo')['SHA512'], '') def test_formats_target_correctly_for_symlink(self): self.st[summainlib.RESULT_MODE] = stat.S_IFLNK | 0777 self.assertEqual(self.new('foo')['Target'], 'symlink') def test_formats_target_correctly_for_regular_file(self): self.assertEqual(self.new('foo')['Target'], '') def test_excludes_unwanted_fields_from_output(self): self.exclude = ['mtime'] fso = self.new('/foo/bar', mode=stat.S_IFREG) self.assertEqual(fso['Mtime'], '') class FilesystemObjectNormalizedNumbersTests(unittest.TestCase): def setUp(self): self.ino = 0 self.dev = 0 self.nn = summainlib.NumberNormalizer() self.pn = summainlib.SamePath() self.exclude = [] self.checksums = ['SHA1'] def reset(self): self.dev += 1 self.nn.reset() def new(self, name): st = { summainlib.RESULT_INO: self.ino, summainlib.RESULT_DEV: self.dev, summainlib.RESULT_MTIME_SEC: 0, summainlib.RESULT_MTIME_NSEC: 0, summainlib.RESULT_MODE: stat.S_IFREG | 0, summainlib.RESULT_NLINK: 1, summainlib.RESULT_SIZE: 0, summainlib.RESULT_UID: 0, summainlib.RESULT_GID: 0 } self.ino += 1 return summainlib.FilesystemObject( name, self.nn, self.pn, self.exclude, stat_result=st, sha1=FakeChecksummer(), sha224=FakeChecksummer(), sha256=FakeChecksummer(), sha384=FakeChecksummer(), sha512=FakeChecksummer(), md5=FakeChecksummer(), open_file=FakeOpenFile(), readlink=FakeReadlink(self), xattrs={}) def test_inode_numbers_are_repeatable(self): a1 = self.new('foo') a2 = self.new('bar') # Counter lazy evaluation. a1['Dev'] a1['Ino'] a2['Dev'] a2['Ino'] self.reset() b1 = self.new('foo') b2 = self.new('bar') self.assertEqual(a1['Dev'], b1['Dev']) self.assertEqual(a1['Ino'], b1['Ino']) self.assertEqual(a2['Dev'], b2['Dev']) self.assertEqual(a2['Ino'], b2['Ino']) class NumberNormalizerTests(unittest.TestCase): def setUp(self): self.nn = summainlib.NumberNormalizer() def test_returns_1_2_3_regardless_of_input_numbers(self): self.assertEqual([self.nn.get_ino(i) for i in [10, 11, 12]], [1, 2, 3]) def test_returns_1_1_1_when_input_number_is_repeated(self): self.assertEqual([self.nn.get_ino(i) for i in [10, 10, 10]], [1, 1, 1]) class PathNormalizerTests(unittest.TestCase): def setUp(self): self.pn = summainlib.PathNormalizer('secret') def test_returns_different_paths_for_different_inputs(self): self.assertNotEqual(self.pn.normalize('/foo/bar'), self.pn.normalize('/ping/pong')) def test_returns_same_paths_for_same_input(self): self.assertEqual(self.pn.normalize('/foo/bar'), self.pn.normalize('/foo/bar'))