Mercurial > piecrust2
comparison tests/test_pipelines_asset.py @ 974:72f17534d58e
tests: First pass on making unit tests work again.
- Fix all imports
- Add more helper functions to work with mock file-systems
- Simplify some code by running chef directly on the mock FS
- Fix a couple tests
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 17 Oct 2017 01:07:30 -0700 |
parents | |
children | 45ad976712ec |
comparison
equal
deleted
inserted
replaced
973:8419daaa7a0e | 974:72f17534d58e |
---|---|
1 import time | |
2 import os.path | |
3 import shutil | |
4 import inspect | |
5 import pytest | |
6 from piecrust.pipelines.asset import get_filtered_processors | |
7 from piecrust.pipelines.records import MultiRecord | |
8 from piecrust.processing.base import SimpleFileProcessor | |
9 from .mockutil import mock_fs, mock_fs_scope | |
10 | |
11 | |
12 class FooProcessor(SimpleFileProcessor): | |
13 def __init__(self, exts=None, open_func=None): | |
14 exts = exts or {'foo', 'foo'} | |
15 super(FooProcessor, self).__init__({exts[0]: exts[1]}) | |
16 self.PROCESSOR_NAME = exts[0] | |
17 self.open_func = open_func or open | |
18 | |
19 def _doProcess(self, in_path, out_path): | |
20 with self.open_func(in_path, 'r') as f: | |
21 text = f.read() | |
22 with self.open_func(out_path, 'w') as f: | |
23 f.write("%s: %s" % (self.PROCESSOR_NAME.upper(), text)) | |
24 return True | |
25 | |
26 | |
27 class NoopProcessor(SimpleFileProcessor): | |
28 def __init__(self, exts): | |
29 super(NoopProcessor, self).__init__({exts[0]: exts[1]}) | |
30 self.PROCESSOR_NAME = exts[0] | |
31 self.processed = [] | |
32 | |
33 def _doProcess(self, in_path, out_path): | |
34 self.processed.append(in_path) | |
35 shutil.copyfile(in_path, out_path) | |
36 return True | |
37 | |
38 | |
39 def _get_test_fs(processors=None): | |
40 if processors is None: | |
41 processors = 'copy' | |
42 return (mock_fs() | |
43 .withDir('counter') | |
44 .withConfig({ | |
45 'pipelines': { | |
46 'asset': { | |
47 'processors': processors | |
48 } | |
49 } | |
50 })) | |
51 | |
52 | |
53 def _create_test_plugin(fs, *, foo_exts=None, noop_exts=None): | |
54 src = [ | |
55 'from piecrust.plugins.base import PieCrustPlugin', | |
56 'from piecrust.processing.base import SimpleFileProcessor'] | |
57 | |
58 foo_lines = inspect.getsourcelines(FooProcessor) | |
59 src += [''] | |
60 src += map(lambda l: l.rstrip('\n'), foo_lines[0]) | |
61 | |
62 noop_lines = inspect.getsourcelines(NoopProcessor) | |
63 src += [''] | |
64 src += map(lambda l: l.rstrip('\n'), noop_lines[0]) | |
65 | |
66 src += [ | |
67 '', | |
68 'class FooNoopPlugin(PieCrustPlugin):', | |
69 ' def getProcessors(self):', | |
70 ' yield FooProcessor(%s)' % repr(foo_exts), | |
71 ' yield NoopProcessor(%s)' % repr(noop_exts), | |
72 '', | |
73 '__piecrust_plugin__ = FooNoopPlugin'] | |
74 | |
75 fs.withFile('kitchen/plugins/foonoop.py', src) | |
76 | |
77 | |
78 def _bake_assets(fs): | |
79 fs.runChef('bake', '-p', 'asset') | |
80 | |
81 | |
82 def test_empty(): | |
83 fs = _get_test_fs() | |
84 with mock_fs_scope(fs): | |
85 expected = {} | |
86 assert expected == fs.getStructure('counter') | |
87 _bake_assets(fs) | |
88 expected = {} | |
89 assert expected == fs.getStructure('counter') | |
90 | |
91 | |
92 def test_one_file(): | |
93 fs = (_get_test_fs() | |
94 .withFile('kitchen/assets/something.html', 'A test file.')) | |
95 with mock_fs_scope(fs): | |
96 expected = {} | |
97 assert expected == fs.getStructure('counter') | |
98 _bake_assets(fs) | |
99 expected = {'something.html': 'A test file.'} | |
100 assert expected == fs.getStructure('counter') | |
101 | |
102 | |
103 def test_one_level_dirtyness(): | |
104 fs = (_get_test_fs() | |
105 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
106 with mock_fs_scope(fs): | |
107 _bake_assets(fs) | |
108 expected = {'blah.foo': 'A test file.'} | |
109 assert expected == fs.getStructure('counter') | |
110 mtime = os.path.getmtime(fs.path('/counter/blah.foo')) | |
111 assert abs(time.time() - mtime) <= 2 | |
112 | |
113 time.sleep(1) | |
114 _bake_assets(fs) | |
115 assert expected == fs.getStructure('counter') | |
116 assert mtime == os.path.getmtime(fs.path('/counter/blah.foo')) | |
117 | |
118 time.sleep(1) | |
119 fs.withFile('kitchen/assets/blah.foo', 'A new test file.') | |
120 _bake_assets(fs) | |
121 expected = {'blah.foo': 'A new test file.'} | |
122 assert expected == fs.getStructure('counter') | |
123 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) | |
124 | |
125 | |
126 def test_two_levels_dirtyness(): | |
127 fs = (_get_test_fs() | |
128 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
129 _create_test_plugin(fs, foo_exts=('foo', 'bar')) | |
130 with mock_fs_scope(fs): | |
131 _bake_assets(fs) | |
132 expected = {'blah.bar': 'FOO: A test file.'} | |
133 assert expected == fs.getStructure('counter') | |
134 mtime = os.path.getmtime(fs.path('/counter/blah.bar')) | |
135 assert abs(time.time() - mtime) <= 2 | |
136 | |
137 time.sleep(1) | |
138 _bake_assets(fs) | |
139 assert expected == fs.getStructure('counter') | |
140 assert mtime == os.path.getmtime(fs.path('/counter/blah.bar')) | |
141 | |
142 time.sleep(1) | |
143 fs.withFile('kitchen/assets/blah.foo', 'A new test file.') | |
144 _bake_assets(fs) | |
145 expected = {'blah.bar': 'FOO: A new test file.'} | |
146 assert expected == fs.getStructure('counter') | |
147 assert mtime < os.path.getmtime(fs.path('/counter/blah.bar')) | |
148 | |
149 | |
150 def test_removed(): | |
151 fs = (_get_test_fs() | |
152 .withFile('kitchen/assets/blah1.foo', 'A test file.') | |
153 .withFile('kitchen/assets/blah2.foo', 'Ooops')) | |
154 with mock_fs_scope(fs): | |
155 expected = { | |
156 'blah1.foo': 'A test file.', | |
157 'blah2.foo': 'Ooops'} | |
158 assert expected == fs.getStructure('kitchen/assets') | |
159 _bake_assets(fs) | |
160 assert expected == fs.getStructure('counter') | |
161 | |
162 time.sleep(1) | |
163 os.remove(fs.path('/kitchen/assets/blah2.foo')) | |
164 expected = { | |
165 'blah1.foo': 'A test file.'} | |
166 assert expected == fs.getStructure('kitchen/assets') | |
167 _bake_assets(1) | |
168 assert expected == fs.getStructure('counter') | |
169 | |
170 | |
171 def test_record_version_change(): | |
172 fs = (_get_test_fs() | |
173 .withFile('kitchen/assets/blah.foo', 'A test file.')) | |
174 _create_test_plugin(fs, foo_exts=('foo', 'foo')) | |
175 with mock_fs_scope(fs): | |
176 _bake_assets(fs) | |
177 assert os.path.exists(fs.path('/counter/blah.foo')) is True | |
178 mtime = os.path.getmtime(fs.path('/counter/blah.foo')) | |
179 | |
180 time.sleep(1) | |
181 _bake_assets(fs) | |
182 assert mtime == os.path.getmtime(fs.path('/counter/blah.foo')) | |
183 | |
184 time.sleep(1) | |
185 MultiRecord.RECORD_VERSION += 1 | |
186 try: | |
187 _bake_assets(fs) | |
188 assert mtime < os.path.getmtime(fs.path('/counter/blah.foo')) | |
189 finally: | |
190 MultiRecord.RECORD_VERSION -= 1 | |
191 | |
192 | |
193 @pytest.mark.parametrize('patterns, expected', [ | |
194 (['_'], | |
195 {'something.html': 'A test file.'}), | |
196 (['html'], | |
197 {}), | |
198 (['/^_/'], | |
199 {'something.html': 'A test file.', | |
200 'foo': {'_important.html': 'Important!'}}) | |
201 ]) | |
202 def test_ignore_pattern(patterns, expected): | |
203 fs = (_get_test_fs() | |
204 .withFile('kitchen/assets/something.html', 'A test file.') | |
205 .withFile('kitchen/assets/_hidden.html', 'Shhh') | |
206 .withFile('kitchen/assets/foo/_important.html', 'Important!')) | |
207 fs.withConfig({'pipelines': {'asset': {'ignore': patterns}}}) | |
208 with mock_fs_scope(fs): | |
209 assert {} == fs.getStructure('counter') | |
210 _bake_assets(fs) | |
211 assert expected == fs.getStructure('counter') | |
212 | |
213 | |
214 @pytest.mark.parametrize('names, expected', [ | |
215 ('all', ['cleancss', 'compass', 'copy', 'concat', 'less', 'requirejs', | |
216 'sass', 'sitemap', 'uglifyjs', 'pygments_style']), | |
217 ('all -sitemap', ['cleancss', 'copy', 'compass', 'concat', 'less', | |
218 'requirejs', 'sass', 'uglifyjs', 'pygments_style']), | |
219 ('-sitemap -less -sass all', ['cleancss', 'copy', 'compass', 'concat', | |
220 'requirejs', 'uglifyjs', | |
221 'pygments_style']), | |
222 ('copy', ['copy']), | |
223 ('less sass', ['less', 'sass']) | |
224 ]) | |
225 def test_filter_processor(names, expected): | |
226 fs = mock_fs().withConfig() | |
227 with mock_fs_scope(fs): | |
228 app = fs.getApp() | |
229 processors = app.plugin_loader.getProcessors() | |
230 procs = get_filtered_processors(processors, names) | |
231 actual = [p.PROCESSOR_NAME for p in procs] | |
232 assert sorted(actual) == sorted(expected) | |
233 |