1#!/usr/bin/env python
2# Copyright 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from copy import deepcopy
7import unittest
8
9from file_system import FileNotFoundError, StatInfo
10from patched_file_system import PatchedFileSystem
11from test_file_system import TestFileSystem
12from test_patcher import TestPatcher
13
14_TEST_FS_DATA = {
15  'dir1': {
16    'file1.html': 'This is dir1/file1.html',
17    'unmodified': {
18      '1': '1',
19      '2': '',
20    },
21  },
22  'dir2': {
23    'subdir1': {
24      'sub1.txt': 'in subdir(1)',
25      'sub2.txt': 'in subdir(2)',
26      'sub3.txt': 'in subdir(3)',
27    },
28  },
29  'dir3': {
30  },
31  'dir4': {
32    'one.txt': '',
33  },
34  'dir5': {
35    'subdir': {
36      '1.txt': '555',
37    },
38  },
39  'test1.txt': 'test1',
40  'test2.txt': 'test2',
41}
42
43_TEST_PATCH_VERSION = '1001'
44_TEST_PATCH_FILES = (
45  # Added
46  [
47    'test3.txt',
48    'dir1/file2.html',
49    'dir1/newsubdir/a.js',
50    'newdir/1.html',
51  ],
52  # Deleted
53  [
54    'test2.txt',
55    'dir2/subdir1/sub1.txt',
56    'dir4/one.txt',
57    'dir5/subdir/1.txt',
58  ],
59  # Modified
60  [
61    'dir2/subdir1/sub2.txt',
62  ]
63)
64_TEST_PATCH_DATA = {
65  'test3.txt': 'test3 is added.',
66  'dir1/file2.html': 'This is dir1/file2.html',
67  'dir1/newsubdir/a.js': 'This is a.js',
68  'newdir/1.html': 'This comes from a new dir.',
69  'dir2/subdir1/sub2.txt': 'in subdir',
70}
71
72class PatchedFileSystemTest(unittest.TestCase):
73  def setUp(self):
74    self._patcher = TestPatcher(_TEST_PATCH_VERSION,
75                                _TEST_PATCH_FILES,
76                                _TEST_PATCH_DATA)
77    self._host_file_system = TestFileSystem(_TEST_FS_DATA)
78    self._file_system = PatchedFileSystem(self._host_file_system,
79                                          self._patcher)
80
81  def testRead(self):
82    expected = deepcopy(_TEST_PATCH_DATA)
83    # Files that are not modified.
84    expected.update({
85      'dir2/subdir1/sub3.txt': 'in subdir(3)',
86      'dir1/file1.html': 'This is dir1/file1.html',
87    })
88
89    for key in expected:
90      self.assertEqual(expected[key], self._file_system.ReadSingle(key).Get())
91
92    self.assertEqual(
93        expected,
94        self._file_system.Read(expected.keys()).Get())
95
96    self.assertRaises(FileNotFoundError,
97                      self._file_system.ReadSingle('test2.txt').Get)
98    self.assertRaises(FileNotFoundError,
99                      self._file_system.ReadSingle('dir2/subdir1/sub1.txt').Get)
100    self.assertRaises(FileNotFoundError,
101                      self._file_system.ReadSingle('not_existing').Get)
102    self.assertRaises(FileNotFoundError,
103                      self._file_system.ReadSingle('dir1/not_existing').Get)
104    self.assertRaises(
105        FileNotFoundError,
106        self._file_system.ReadSingle('dir1/newsubdir/not_existing').Get)
107
108  def testReadDir(self):
109    self.assertEqual(
110        sorted(self._file_system.ReadSingle('dir1/').Get()),
111        sorted(set(self._host_file_system.ReadSingle('dir1/').Get()) |
112               set(('file2.html', 'newsubdir/'))))
113
114    self.assertEqual(
115        sorted(self._file_system.ReadSingle('dir1/newsubdir/').Get()),
116        sorted(['a.js']))
117
118    self.assertEqual(sorted(self._file_system.ReadSingle('dir2/').Get()),
119                     sorted(self._host_file_system.ReadSingle('dir2/').Get()))
120
121    self.assertEqual(
122        sorted(self._file_system.ReadSingle('dir2/subdir1/').Get()),
123        sorted(set(self._host_file_system.ReadSingle('dir2/subdir1/').Get()) -
124               set(('sub1.txt',))))
125
126    self.assertEqual(sorted(self._file_system.ReadSingle('newdir/').Get()),
127                     sorted(['1.html']))
128
129    self.assertEqual(self._file_system.ReadSingle('dir3/').Get(), [])
130
131    self.assertEqual(self._file_system.ReadSingle('dir4/').Get(), [])
132
133    self.assertRaises(FileNotFoundError,
134                      self._file_system.ReadSingle('not_existing_dir/').Get)
135
136  def testStat(self):
137    version = 'patched_%s' % self._patcher.GetVersion()
138    old_version = self._host_file_system.Stat('dir1/file1.html').version
139
140    # Stat an unmodified file.
141    self.assertEqual(self._file_system.Stat('dir1/file1.html'),
142                     self._host_file_system.Stat('dir1/file1.html'))
143
144    # Stat an unmodified directory.
145    self.assertEqual(self._file_system.Stat('dir1/unmodified/'),
146                     self._host_file_system.Stat('dir1/unmodified/'))
147
148    # Stat a modified directory.
149    self.assertEqual(self._file_system.Stat('dir2/'),
150                     StatInfo(version, {'subdir1/': version}))
151    self.assertEqual(self._file_system.Stat('dir2/subdir1/'),
152                     StatInfo(version, {'sub2.txt': version,
153                                        'sub3.txt': old_version}))
154
155    # Stat a modified directory with new files.
156    expected = self._host_file_system.Stat('dir1/')
157    expected.version = version
158    expected.child_versions.update({'file2.html': version,
159                                    'newsubdir/': version})
160    self.assertEqual(self._file_system.Stat('dir1/'),
161                     expected)
162
163    # Stat an added directory.
164    self.assertEqual(self._file_system.Stat('dir1/newsubdir/'),
165                     StatInfo(version, {'a.js': version}))
166    self.assertEqual(self._file_system.Stat('dir1/newsubdir/a.js'),
167                     StatInfo(version))
168    self.assertEqual(self._file_system.Stat('newdir/'),
169                     StatInfo(version, {'1.html': version}))
170    self.assertEqual(self._file_system.Stat('newdir/1.html'),
171                     StatInfo(version))
172
173    # Stat files removed in the patch.
174    self.assertRaises(FileNotFoundError, self._file_system.Stat,
175        'dir2/subdir1/sub1.txt')
176    self.assertRaises(FileNotFoundError, self._file_system.Stat,
177        'dir4/one.txt')
178
179    # Stat empty directories.
180    self.assertEqual(self._file_system.Stat('dir3/'),
181                     StatInfo(old_version, {}))
182    self.assertEqual(self._file_system.Stat('dir4/'),
183                     StatInfo(version, {}))
184    self.assertEqual(self._file_system.Stat('dir5/subdir/'),
185                     StatInfo(version, {}))
186
187    # Stat empty (after patch) directory's parent
188    self.assertEqual(self._file_system.Stat('dir5/'),
189                     StatInfo(version, {'subdir/': version}))
190
191    # Stat files that don't exist either before or after patching.
192    self.assertRaises(FileNotFoundError, self._file_system.Stat,
193        'not_existing/')
194    self.assertRaises(FileNotFoundError, self._file_system.Stat,
195        'dir1/not_existing/')
196    self.assertRaises(FileNotFoundError, self._file_system.Stat,
197        'dir1/not_existing')
198
199if __name__ == '__main__':
200  unittest.main()
201