Merged revisions 2136-2200,2202-2290,2292-2301 via svnmerge from
[scons.git] / src / engine / SCons / CacheDirTests.py
1 #
2 # __COPYRIGHT__
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import os.path
27 import shutil
28 import sys
29 import unittest
30
31 from TestCmd import TestCmd
32
33 import SCons.CacheDir
34
35 built_it = None
36
37 class Action:
38     def __call__(self, targets, sources, env, errfunc, **kw):
39         global built_it
40         if kw.get('execute', 1):
41             built_it = 1
42         return 0
43
44 class Builder:
45     def __init__(self, environment, action):
46         self.env = environment
47         self.action = action
48         self.overrides = {}
49
50 class Environment:
51     def __init__(self, cachedir):
52         self.cachedir = cachedir
53     def Override(self, overrides):
54         return self
55     def get_CacheDir(self):
56         return self.cachedir
57
58 class BaseTestCase(unittest.TestCase):
59     """
60     Base fixtures common to our other unittest classes.
61     """
62     def setUp(self):
63         self.test = TestCmd(workdir='')
64
65         import SCons.Node.FS
66         self.fs = SCons.Node.FS.FS()
67
68         self._CacheDir = SCons.CacheDir.CacheDir('cache')
69
70     def File(self, name, bsig=None, action=Action()):
71         node = self.fs.File(name)
72         node.builder_set(Builder(Environment(self._CacheDir), action))
73         if bsig:
74             node.binfo = node.BuildInfo(node)
75             node.binfo.ninfo.bsig = bsig
76         return node
77
78 class CacheDirTestCase(BaseTestCase):
79     """
80     Test calling CacheDir code directly.
81     """
82     def test_cachepath(self):
83         """Test the cachepath() method"""
84
85         # Verify how the cachepath() method determines the name
86         # of the file in cache.
87         def my_collect(list):
88             return list[0]
89         save_collect = SCons.Sig.MD5.collect
90         SCons.Sig.MD5.collect = my_collect
91
92         try:
93             f5 = self.File("cd.f5", 'a_fake_bsig')
94             result = self._CacheDir.cachepath(f5)
95             dirname = os.path.join('cache', 'A')
96             filename = os.path.join(dirname, 'a_fake_bsig')
97             assert result == (dirname, filename), result
98         finally:
99             SCons.Sig.MD5.collect = save_collect
100
101 class FileTestCase(BaseTestCase):
102     """
103     Test calling CacheDir code through Node.FS.File interfaces.
104     """
105     # These tests were originally in Nodes/FSTests.py and got moved
106     # when the CacheDir support was refactored into its own module.
107     # Look in the history for Node/FSTests.py if any of this needs
108     # to be re-examined.
109     def retrieve_succeed(self, target, source, env, execute=1):
110         self.retrieved.append(target)
111         return 0
112
113     def retrieve_fail(self, target, source, env, execute=1):
114         self.retrieved.append(target)
115         return 1
116
117     def push(self, target, source, env):
118         self.pushed.append(target)
119         return 0
120
121     def test_CacheRetrieve(self):
122         """Test the CacheRetrieve() function"""
123
124         save_CacheRetrieve = SCons.CacheDir.CacheRetrieve
125         self.retrieved = []
126
127         f1 = self.File("cd.f1")
128         try:
129             SCons.CacheDir.CacheRetrieve = self.retrieve_succeed
130             self.retrieved = []
131             built_it = None
132
133             r = f1.retrieve_from_cache()
134             assert r == 1, r
135             assert self.retrieved == [f1], self.retrieved
136             assert built_it is None, built_it
137
138             SCons.CacheDir.CacheRetrieve = self.retrieve_fail
139             self.retrieved = []
140             built_it = None
141
142             r = f1.retrieve_from_cache()
143             assert not r, r
144             assert self.retrieved == [f1], self.retrieved
145             assert built_it is None, built_it
146         finally:
147             SCons.CacheDir.CacheRetrieve = save_CacheRetrieve
148
149     def test_CacheRetrieveSilent(self):
150         """Test the CacheRetrieveSilent() function"""
151
152         save_CacheRetrieveSilent = SCons.CacheDir.CacheRetrieveSilent
153
154         SCons.CacheDir.cache_show = 1
155
156         f2 = self.File("cd.f2", 'f2_bsig')
157         try:
158             SCons.CacheDir.CacheRetrieveSilent = self.retrieve_succeed
159             self.retrieved = []
160             built_it = None
161
162             r = f2.retrieve_from_cache()
163             assert r == 1, r
164             assert self.retrieved == [f2], self.retrieved
165             assert built_it is None, built_it
166
167             SCons.CacheDir.CacheRetrieveSilent = self.retrieve_fail
168             self.retrieved = []
169             built_it = None
170
171             r = f2.retrieve_from_cache()
172             assert r is False, r
173             assert self.retrieved == [f2], self.retrieved
174             assert built_it is None, built_it
175         finally:
176             SCons.CacheDir.CacheRetrieveSilent = save_CacheRetrieveSilent
177
178     def test_CachePush(self):
179         """Test the CachePush() function"""
180
181         save_CachePush = SCons.CacheDir.CachePush
182
183         SCons.CacheDir.CachePush = self.push
184
185         try:
186             self.pushed = []
187
188             cd_f3 = self.test.workpath("cd.f3")
189             f3 = self.File(cd_f3)
190             f3.built()
191             assert self.pushed == [], self.pushed
192             self.test.write(cd_f3, "cd.f3\n")
193             f3.built()
194             assert self.pushed == [f3], self.pushed
195
196             self.pushed = []
197
198             cd_f4 = self.test.workpath("cd.f4")
199             f4 = self.File(cd_f4)
200             f4.visited()
201             assert self.pushed == [], self.pushed
202             self.test.write(cd_f4, "cd.f4\n")
203             f4.clear()
204             f4.visited()
205             assert self.pushed == [], self.pushed
206             SCons.CacheDir.cache_force = 1
207             f4.clear()
208             f4.visited()
209             assert self.pushed == [f4], self.pushed
210         finally:
211             SCons.CacheDir.CachePush = save_CachePush
212
213     def test_no_bsig(self):
214         """Test that no bsig raises an InternalError"""
215
216         f6 = self.File("cd.f6")
217         f6.binfo = f6.BuildInfo(f6)
218         exc_caught = 0
219         try:
220             cp = self._CacheDir.cachepath(f6)
221         except SCons.Errors.InternalError:
222             exc_caught = 1
223         assert exc_caught
224
225     def test_warning(self):
226         """Test raising a warning if we can't copy a file to cache."""
227
228         test = TestCmd(workdir='')
229
230         save_copy2 = shutil.copy2
231         def copy2(src, dst):
232             raise OSError
233         shutil.copy2 = copy2
234         save_mkdir = os.mkdir
235         def mkdir(dir, mode=0):
236             pass
237         os.mkdir = mkdir
238         old_warn_exceptions = SCons.Warnings.warningAsException(1)
239         SCons.Warnings.enableWarningClass(SCons.Warnings.CacheWriteErrorWarning)
240
241         try:
242             cd_f7 = self.test.workpath("cd.f7")
243             self.test.write(cd_f7, "cd.f7\n")
244             f7 = self.File(cd_f7, 'f7_bsig')
245
246             warn_caught = 0
247             try:
248                 f7.built()
249             except SCons.Warnings.CacheWriteErrorWarning:
250                 warn_caught = 1
251             assert warn_caught
252         finally:
253             shutil.copy2 = save_copy2
254             os.mkdir = save_mkdir
255             SCons.Warnings.warningAsException(old_warn_exceptions)
256             SCons.Warnings.suppressWarningClass(SCons.Warnings.CacheWriteErrorWarning)
257
258     def test_no_strfunction(self):
259         """Test handling no strfunction() for an action."""
260
261         save_CacheRetrieveSilent = SCons.CacheDir.CacheRetrieveSilent
262
263         f8 = self.File("cd.f8", 'f8_bsig')
264         try:
265             SCons.CacheDir.CacheRetrieveSilent = self.retrieve_succeed
266             self.retrieved = []
267             built_it = None
268
269             r = f8.retrieve_from_cache()
270             assert r == 1, r
271             assert self.retrieved == [f8], self.retrieved
272             assert built_it is None, built_it
273
274             SCons.CacheDir.CacheRetrieveSilent = self.retrieve_fail
275             self.retrieved = []
276             built_it = None
277
278             r = f8.retrieve_from_cache()
279             assert r is False, r
280             assert self.retrieved == [f8], self.retrieved
281             assert built_it is None, built_it
282         finally:
283             SCons.CacheDir.CacheRetrieveSilent = save_CacheRetrieveSilent
284
285 if __name__ == "__main__":
286     suite = unittest.TestSuite()
287     tclasses = [
288         CacheDirTestCase,
289         FileTestCase,
290     ]
291     for tclass in tclasses:
292         names = unittest.getTestCaseNames(tclass, 'test_')
293         suite.addTests(map(tclass, names))
294     if not unittest.TextTestRunner().run(suite).wasSuccessful():
295         sys.exit(1)