Remove all features deprecated in 0.93 or earlier.
[scons.git] / src / engine / SCons / Options / OptionsTests.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 string
27 import sys
28 import unittest
29 import TestSCons
30
31 import SCons.Options
32 import SCons.Util
33 import SCons.Warnings
34
35
36 class Environment:
37     def __init__(self):
38         self.dict = {}
39     def subst(self, x):
40         return SCons.Util.scons_subst(x, self)
41     def __setitem__(self, key, value):
42         self.dict[key] = value
43     def __getitem__(self, key):
44         return self.dict[key]
45     def has_key(self, key):
46         return self.dict.has_key(key)
47     def Dictionary(self):
48         return self.dict
49
50
51 def check(key, value, env):
52     assert int(value) == 6 * 9, "key %s = %s" % (key, repr(value))
53     
54 # Check saved option file by executing and comparing against
55 # the expected dictionary
56 def checkSave(file, expected):
57     gdict = {}
58     ldict = {}
59     execfile(file, gdict, ldict)
60     assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict)
61
62 class OptionsTestCase(unittest.TestCase):
63
64     def test_Add(self):
65         """Test adding to an Options object"""
66         opts = SCons.Options.Options()
67
68         opts.Add('VAR')
69         opts.Add('ANSWER',
70                  'THE answer to THE question',
71                  "42",
72                  check,
73                  lambda x: int(x) + 12)
74
75         o = opts.options[0]
76         assert o.key == 'VAR'
77         assert o.help == ''
78         assert o.default == None
79         assert o.validator == None
80         assert o.converter == None
81
82         o = opts.options[1]
83         assert o.key == 'ANSWER'
84         assert o.help == 'THE answer to THE question'
85         assert o.default == "42"
86         o.validator(o.key, o.converter(o.default), {})
87
88         def test_it(var, opts=opts):
89             exc_caught = None
90             try:
91                 opts.Add(var)
92             except SCons.Errors.UserError:
93                 exc_caught = 1
94             assert exc_caught, "did not catch UserError for '%s'" % var
95         test_it('foo/bar')
96         test_it('foo-bar')
97         test_it('foo.bar')
98
99     def test_AddOptions(self):
100         """Test adding a list of options to an Options object"""
101         opts = SCons.Options.Options()
102
103         opts.AddOptions(('VAR2',),
104                         ('ANSWER2',
105                          'THE answer to THE question',
106                          "42",
107                          check,
108                          lambda x: int(x) + 12))
109
110         o = opts.options[0]
111         assert o.key == 'VAR2', o.key
112         assert o.help == '', o.help
113         assert o.default == None, o.default
114         assert o.validator == None, o.validator
115         assert o.converter == None, o.converter
116
117         o = opts.options[1]
118         assert o.key == 'ANSWER2', o.key
119         assert o.help == 'THE answer to THE question', o.help
120         assert o.default == "42", o.default
121         o.validator(o.key, o.converter(o.default), {})
122
123     def test_Update(self):
124         """Test updating an Environment"""
125
126         # Test that a default value is validated correctly.
127         test = TestSCons.TestSCons()
128         file = test.workpath('custom.py')
129         opts = SCons.Options.Options(file)
130         
131         opts.Add('ANSWER',
132                  'THE answer to THE question',
133                  "42",
134                  check,
135                  lambda x: int(x) + 12)
136
137         env = Environment()
138         opts.Update(env)
139         assert env['ANSWER'] == 54
140
141         env = Environment()
142         opts.Update(env, {})
143         assert env['ANSWER'] == 54
144
145         # Test that a bad value from the file is used and
146         # validation fails correctly.
147         test = TestSCons.TestSCons()
148         file = test.workpath('custom.py')
149         test.write('custom.py', 'ANSWER=54')
150         opts = SCons.Options.Options(file)
151         
152         opts.Add('ANSWER',
153                  'THE answer to THE question',
154                  "42",
155                  check,
156                  lambda x: int(x) + 12)
157
158         env = Environment()
159         exc_caught = None
160         try:
161             opts.Update(env)
162         except AssertionError:
163             exc_caught = 1
164         assert exc_caught, "did not catch expected assertion"
165
166         env = Environment()
167         exc_caught = None
168         try:
169             opts.Update(env, {})
170         except AssertionError:
171             exc_caught = 1
172         assert exc_caught, "did not catch expected assertion"
173
174         # Test that a good value from the file is used and validated.
175         test = TestSCons.TestSCons()
176         file = test.workpath('custom.py')
177         test.write('custom.py', 'ANSWER=42')
178         opts = SCons.Options.Options(file)
179         
180         opts.Add('ANSWER',
181                  'THE answer to THE question',
182                  "10",
183                  check,
184                  lambda x: int(x) + 12)
185
186         env = Environment()
187         opts.Update(env)
188         assert env['ANSWER'] == 54
189
190         env = Environment()
191         opts.Update(env, {})
192         assert env['ANSWER'] == 54
193
194         # Test that a bad value from an args dictionary passed to
195         # Update() is used and validation fails correctly.
196         test = TestSCons.TestSCons()
197         file = test.workpath('custom.py')
198         test.write('custom.py', 'ANSWER=10')
199         opts = SCons.Options.Options(file)
200         
201         opts.Add('ANSWER',
202                  'THE answer to THE question',
203                  "12",
204                  check,
205                  lambda x: int(x) + 12)
206
207         env = Environment()
208         exc_caught = None
209         try:
210             opts.Update(env, {'ANSWER':'54'})
211         except AssertionError:
212             exc_caught = 1
213         assert exc_caught, "did not catch expected assertion"
214
215         # Test that a good value from an args dictionary
216         # passed to Update() is used and validated.
217         test = TestSCons.TestSCons()
218         file = test.workpath('custom.py')
219         test.write('custom.py', 'ANSWER=10')
220         opts = SCons.Options.Options(file)
221         
222         opts.Add('ANSWER',
223                  'THE answer to THE question',
224                  "12",
225                  check,
226                  lambda x: int(x) + 12)
227
228         env = Environment()
229         opts.Update(env, {'ANSWER':'42'})
230         assert env['ANSWER'] == 54
231
232         # Test against a former bug.  If we supply a converter,
233         # but no default, the value should *not* appear in the
234         # Environment if no value is specified in the options file
235         # or args.
236         test = TestSCons.TestSCons()
237         file = test.workpath('custom.py')
238         opts = SCons.Options.Options(file)
239         
240         opts.Add('ANSWER',
241                  help='THE answer to THE question',
242                  converter=str)
243
244         env = Environment()
245         opts.Update(env, {})
246         assert not env.has_key('ANSWER')
247         
248     def test_args(self):
249         """Test updating an Environment with arguments overridden"""
250
251         # Test that a bad (command-line) argument is used
252         # and the validation fails correctly.
253         test = TestSCons.TestSCons()
254         file = test.workpath('custom.py')
255         test.write('custom.py', 'ANSWER=42')
256         opts = SCons.Options.Options(file, {'ANSWER':54})
257         
258         opts.Add('ANSWER',
259                  'THE answer to THE question',
260                  "42",
261                  check,
262                  lambda x: int(x) + 12)
263
264         env = Environment()
265         exc_caught = None
266         try:
267             opts.Update(env)
268         except AssertionError:
269             exc_caught = 1
270         assert exc_caught, "did not catch expected assertion"
271
272         # Test that a good (command-line) argument is used and validated.
273         test = TestSCons.TestSCons()
274         file = test.workpath('custom.py')
275         test.write('custom.py', 'ANSWER=54')
276         opts = SCons.Options.Options(file, {'ANSWER':42})
277         
278         opts.Add('ANSWER',
279                  'THE answer to THE question',
280                  "54",
281                  check,
282                  lambda x: int(x) + 12)
283
284         env = Environment()
285         opts.Update(env)
286         assert env['ANSWER'] == 54
287
288         # Test that a (command-line) argument is overridden by a dictionary
289         # supplied to Update() and the dictionary value is validated correctly.
290         test = TestSCons.TestSCons()
291         file = test.workpath('custom.py')
292         test.write('custom.py', 'ANSWER=54')
293         opts = SCons.Options.Options(file, {'ANSWER':54})
294         
295         opts.Add('ANSWER',
296                  'THE answer to THE question',
297                  "54",
298                  check,
299                  lambda x: int(x) + 12)
300
301         env = Environment()
302         opts.Update(env, {'ANSWER':42})
303         assert env['ANSWER'] == 54
304
305     def test_Save(self):
306         """Testing saving Options"""
307
308         test = TestSCons.TestSCons()
309         cache_file = test.workpath('cached.options')
310         opts = SCons.Options.Options()
311         
312         # test saving out empty file
313         opts.Add('OPT_VAL',
314                  'An option to test',
315                  21,
316                  None,
317                  None)
318         opts.Add('OPT_VAL_2',
319                  default='foo')
320         opts.Add('OPT_VAL_3',
321                  default=1)
322
323         env = Environment()
324         opts.Update(env, {'OPT_VAL_3' : 2})
325         assert env['OPT_VAL'] == 21
326         assert env['OPT_VAL_2'] == 'foo'
327         assert env['OPT_VAL_3'] == 2
328         env['OPT_VAL_2'] = 'bar'
329         opts.Save(cache_file, env)
330         checkSave(cache_file, { 'OPT_VAL_2' : 'bar',
331                                 'OPT_VAL_3' : 2 })
332
333         # Test against some old bugs
334         class Foo:
335             def __init__(self, x):
336                 self.x = x
337             def __str__(self):
338                 return self.x
339             
340         test = TestSCons.TestSCons()
341         cache_file = test.workpath('cached.options')
342         opts = SCons.Options.Options()
343         
344         opts.Add('THIS_USED_TO_BREAK',
345                  'An option to test',
346                  "Default")
347
348         opts.Add('THIS_ALSO_BROKE',
349                  'An option to test',
350                  "Default2")
351         
352         opts.Add('THIS_SHOULD_WORK',
353                  'An option to test',
354                  Foo('bar'))
355         
356         env = Environment()
357         opts.Update(env, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String",
358                            'THIS_ALSO_BROKE' : "\\Escape\nSequences\t",
359                            'THIS_SHOULD_WORK' : Foo('baz') })
360         opts.Save(cache_file, env)
361         checkSave(cache_file, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String",
362                                 'THIS_ALSO_BROKE' : "\\Escape\nSequences\t",
363                                 'THIS_SHOULD_WORK' : 'baz' })
364
365     def test_GenerateHelpText(self):
366         opts = SCons.Options.Options()
367
368         opts.Add('ANSWER',
369                  'THE answer to THE question',
370                  "42",
371                  check,
372                  lambda x: int(x) + 12)
373
374         opts.Add('B',
375                  'b - alpha test',
376                  "42",
377                  check,
378                  lambda x: int(x) + 12)
379
380         opts.Add('A',
381                  'a - alpha test',
382                  "42",
383                  check,
384                  lambda x: int(x) + 12)
385
386         env = Environment()
387         opts.Update(env, {})
388
389         expect = """
390 ANSWER: THE answer to THE question
391     default: 42
392     actual: 54
393
394 B: b - alpha test
395     default: 42
396     actual: 54
397
398 A: a - alpha test
399     default: 42
400     actual: 54
401 """
402
403         text = opts.GenerateHelpText(env)
404         assert text == expect, text
405
406         expectAlpha = """
407 A: a - alpha test
408     default: 42
409     actual: 54
410
411 ANSWER: THE answer to THE question
412     default: 42
413     actual: 54
414
415 B: b - alpha test
416     default: 42
417     actual: 54
418 """
419         text = opts.GenerateHelpText(env, sort=cmp)
420         assert text == expectAlpha, text
421         
422 if __name__ == "__main__":
423     suite = unittest.makeSuite(OptionsTestCase, 'test_')
424     if not unittest.TextTestRunner().run(suite).wasSuccessful():
425         sys.exit(1)