allow mandatory value (see 9ddf100118d913c2f4225cca1adb65317b512d84 for more details)
[tiramisu.git] / test / test_option_calculation.py
1 import autopath
2 from py.test import raises
3
4 from tiramisu.setting import groups
5 from tiramisu.config import Config
6 from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
7     StrOption, OptionDescription
8 from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError
9
10
11 def return_val():
12     return 'val'
13
14
15 def return_list():
16     return ['val', 'val']
17
18
19 def return_value(value):
20     return value
21
22
23 def make_description():
24     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
25     gcdummy = BoolOption('dummy', 'dummy', default=False)
26     objspaceoption = ChoiceOption('objspace', 'Object space',
27                                   ('std', 'thunk'), 'std')
28     booloption = BoolOption('bool', 'Test boolean option', default=True)
29     intoption = IntOption('int', 'Test int option', default=0)
30     intoption2 = IntOption('int', 'Test int option', default=0)
31     floatoption = FloatOption('float', 'Test float option', default=2.3)
32     stroption = StrOption('str', 'Test string option', default="abc")
33     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
34     wantref_option = BoolOption('wantref', 'Test requires', default=False,
35                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
36     wantframework_option = BoolOption('wantframework', 'Test requires',
37                                       default=False,
38                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
39     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption, intoption2])
40     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
41                               wantref_option, stroption,
42                               wantframework_option,
43                               intoption, boolop])
44     return descr
45
46
47 def make_description_duplicates():
48     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
49     ## dummy 1
50     gcdummy = BoolOption('dummy', 'dummy', default=False)
51     objspaceoption = ChoiceOption('objspace', 'Object space',
52                                   ('std', 'thunk'), 'std')
53     booloption = BoolOption('bool', 'Test boolean option', default=True)
54     intoption = IntOption('int', 'Test int option', default=0)
55     floatoption = FloatOption('float', 'Test float option', default=2.3)
56     stroption = StrOption('str', 'Test string option', default="abc")
57     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
58     wantref_option = BoolOption('wantref', 'Test requires', default=False,
59                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
60     wantframework_option = BoolOption('wantframework', 'Test requires',
61                                       default=False,
62                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
63     # dummy2 (same path)
64     gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
65     # dummy3 (same name)
66     gcdummy3 = BoolOption('dummy', 'dummy2', default=True)
67     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, gcdummy2, floatoption])
68     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
69                               wantref_option, stroption,
70                               wantframework_option,
71                               intoption, boolop, gcdummy3])
72     return descr
73
74
75 def test_identical_paths():
76     """If in the schema (the option description) there is something that
77     have the same name, an exection is raised
78     """
79     raises(ConflictError, "make_description_duplicates()")
80
81
82 def make_description2():
83     gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
84     gcdummy = BoolOption('dummy', 'dummy', default=False)
85
86     floatoption = FloatOption('float', 'Test float option', default=2.3)
87
88     objspaceoption = ChoiceOption('objspace', 'Object space',
89                                   ['std', 'thunk'], 'std')
90     booloption = BoolOption('bool', 'Test boolean option', default=True)
91     intoption = IntOption('int', 'Test int option', default=0)
92     stroption = StrOption('str', 'Test string option', default="abc")
93     # first multi
94     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
95     boolop.enable_multi()
96     wantref_option = BoolOption('wantref', 'Test requires', default=False,
97                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
98     # second multi
99     wantframework_option = BoolOption('wantframework', 'Test requires',
100                                       default=False,
101                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
102     wantframework_option.enable_multi()
103
104     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
105     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
106                               wantref_option, stroption,
107                               wantframework_option,
108                               intoption, boolop])
109     return descr
110
111
112 # FIXME: il faudra tester les validations sur les multis
113 #def test_multi_constraints():
114 #    "a multi in a constraint has to have the same length"
115 #    descr = make_description2()
116 #    cfg = Config(descr)
117 #    cfg.boolop = [True, True, False]
118 #    cfg.wantframework = [False, False, True]
119 #
120 #def test_multi_raise():
121 #    "a multi in a constraint has to have the same length"
122 #    # FIXME fusionner les deux tests, MAIS PROBLEME :
123 #    # il ne devrait pas etre necessaire de refaire une config
124 #    # si la valeur est modifiee une deuxieme fois ->
125 #    #raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
126 #    #   ExceptionFailure: 'DID NOT RAISE'
127 #    descr = make_description2()
128 #    cfg = Config(descr)
129 #    cfg.boolop = [True]
130 #    raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
131 # ____________________________________________________________
132 # adding dynamically new options description schema
133 #def test_newoption_add_in_descr():
134 #    descr = make_description()
135 #    newoption = BoolOption('newoption', 'dummy twoo', default=False)
136 #    descr.add_child(newoption)
137 #    config = Config(descr)
138 #    assert config.newoption == False
139
140 #def test_newoption_add_in_subdescr():
141 #    descr = make_description()
142 #    newoption = BoolOption('newoption', 'dummy twoo', default=False)
143 #    descr.gc.add_child(newoption)
144 #    config = Config(descr)
145 #    config.bool = False
146 #    assert config.gc.newoption == False
147
148 #def test_newoption_add_in_config():
149 #    descr = make_description()
150 #    config = Config(descr)
151 #    config.bool = False
152 #    newoption = BoolOption('newoption', 'dummy twoo', default=False)
153 #    descr.add_child(newoption)
154 #    config.cfgimpl_update()
155 #    assert config.newoption == False
156 # ____________________________________________________________
157
158
159 def make_description_requires():
160     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
161     gcdummy = BoolOption('dummy', 'dummy', default=False)
162
163     floatoption = FloatOption('float', 'Test float option', default=2.3)
164
165     objspaceoption = ChoiceOption('objspace', 'Object space',
166                                   ('std', 'thunk'), 'std')
167     booloption = BoolOption('bool', 'Test boolean option', default=True)
168     intoption = IntOption('int', 'Test int option', default=0)
169     stroption = StrOption('str', 'Test string option', default="abc",
170                           requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},))
171
172     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
173     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
174                               stroption, intoption])
175     return descr
176
177
178 def test_hidden_if_in():
179     descr = make_description_requires()
180     cfg = Config(descr)
181     setting = cfg.cfgimpl_get_settings()
182     cfg.read_write()
183     stroption = cfg.unwrap_from_path('str')
184     assert not 'hidden' in setting[stroption]
185     cfg.int = 1
186     raises(PropertiesOptionError, "cfg.str")
187     raises(PropertiesOptionError, 'cfg.str="uvw"')
188     assert 'hidden' in setting[stroption]
189
190
191 def test_hidden_if_in_with_group():
192     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
193     gcdummy = BoolOption('dummy', 'dummy', default=False)
194
195     floatoption = FloatOption('float', 'Test float option', default=2.3)
196
197     objspaceoption = ChoiceOption('objspace', 'Object space',
198                                   ('std', 'thunk'), 'std')
199     booloption = BoolOption('bool', 'Test boolean option', default=True)
200     intoption = IntOption('int', 'Test int option', default=0)
201     stroption = StrOption('str', 'Test string option', default="abc")
202     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
203                                 requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},))
204     descr = OptionDescription('constraints', '', [gcgroup, booloption,
205                               objspaceoption, stroption, intoption])
206     cfg = Config(descr)
207     setting = cfg.cfgimpl_get_settings()
208     cfg.read_write()
209     assert not 'hidden' in setting[stroption]
210     cfg.int = 1
211     raises(PropertiesOptionError, "cfg.gc.name")
212
213
214 def test_disabled_with_group():
215     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
216     gcdummy = BoolOption('dummy', 'dummy', default=False)
217
218     floatoption = FloatOption('float', 'Test float option', default=2.3)
219
220     objspaceoption = ChoiceOption('objspace', 'Object space',
221                                   ('std', 'thunk'), 'std')
222     booloption = BoolOption('bool', 'Test boolean option', default=True)
223     intoption = IntOption('int', 'Test int option', default=0)
224     stroption = StrOption('str', 'Test string option', default="abc")
225     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
226                                 requires=({'option': intoption, 'expected': 1, 'action': 'disabled'},))
227     descr = OptionDescription('constraints', '', [gcgroup, booloption,
228                               objspaceoption, stroption, intoption])
229     cfg = Config(descr)
230     cfg.read_write()
231     assert cfg.gc.name
232     cfg.int = 1
233     raises(PropertiesOptionError, "cfg.gc.name")
234 #____________________________________________________________
235
236
237 def make_description_callback():
238     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
239     gcdummy = BoolOption('dummy', 'dummy')
240     objspaceoption = ChoiceOption('objspace', 'Object space',
241                                   ('std', 'thunk'), 'std')
242     booloption = BoolOption('bool', 'Test boolean option', default=True)
243     intoption = IntOption('int', 'Test int option', default=0)
244     floatoption = FloatOption('float', 'Test float option', default=2.3)
245     stroption = StrOption('str', 'Test string option', default="abc")
246     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
247     wantref_option = BoolOption('wantref', 'Test requires', default=False,
248                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
249     wantframework_option = BoolOption('wantframework', 'Test requires',
250                                       default=False,
251                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
252     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
253     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
254                               wantref_option, stroption,
255                               wantframework_option,
256                               intoption, boolop])
257     return descr
258
259
260 def test_has_callback():
261     descr = make_description_callback()
262     # here the owner is 'default'
263     config = Config(descr)
264     setting = config.cfgimpl_get_settings()
265     config.read_write()
266     config.bool = False
267     # because dummy has a callback
268     dummy = config.unwrap_from_path('gc.dummy')
269     setting.append('freeze')
270     setting[dummy].append('frozen')
271     raises(PropertiesOptionError, "config.gc.dummy = True")
272
273
274 def test_freeze_and_has_callback():
275     descr = make_description_callback()
276     config = Config(descr)
277     setting = config.cfgimpl_get_settings()
278     config.read_write()
279     config.bool = False
280     setting = config.cfgimpl_get_settings()
281     setting.append('freeze')
282     dummy = config.unwrap_from_path('gc.dummy')
283     setting[dummy].append('frozen')
284     raises(PropertiesOptionError, "config.gc.dummy = True")
285
286
287 def test_callback():
288     val1 = StrOption('val1', "", callback=return_val)
289     maconfig = OptionDescription('rootconfig', '', [val1])
290     cfg = Config(maconfig)
291     cfg.read_write()
292     assert cfg.val1 == 'val'
293     cfg.val1 = 'new-val'
294     assert cfg.val1 == 'new-val'
295     del(cfg.val1)
296     assert cfg.val1 == 'val'
297
298
299 def test_callback_value():
300     val1 = StrOption('val1', "", 'val')
301     val2 = StrOption('val2', "", callback=return_value, callback_params={'': (('val1', False),)})
302     maconfig = OptionDescription('rootconfig', '', [val1, val2])
303     cfg = Config(maconfig)
304     cfg.read_write()
305     assert cfg.val1 == 'val'
306     assert cfg.val2 == 'val'
307     cfg.val1 = 'new-val'
308     assert cfg.val1 == 'new-val'
309     assert cfg.val2 == 'new-val'
310     del(cfg.val1)
311     assert cfg.val1 == 'val'
312     assert cfg.val2 == 'val'
313
314
315 def test_callback_list():
316     val1 = StrOption('val1', "", callback=return_list)
317     maconfig = OptionDescription('rootconfig', '', [val1])
318     cfg = Config(maconfig)
319     cfg.read_write()
320     raises(ValueError, "cfg.val1")
321
322
323 def test_callback_multi():
324     val1 = StrOption('val1', "", callback=return_val, multi=True)
325     maconfig = OptionDescription('rootconfig', '', [val1])
326     cfg = Config(maconfig)
327     cfg.read_write()
328     assert cfg.val1 == ['val']
329     cfg.val1 = ['new-val']
330     assert cfg.val1 == ['new-val']
331     cfg.val1.append('new-val2')
332     assert cfg.val1 == ['new-val', 'new-val2']
333     del(cfg.val1)
334     assert cfg.val1 == ['val']
335
336
337 def test_callback_multi_value():
338     val1 = StrOption('val1', "", ['val'], multi=True)
339     val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1', False),)})
340     maconfig = OptionDescription('rootconfig', '', [val1, val2])
341     cfg = Config(maconfig)
342     cfg.read_write()
343     assert cfg.val1 == ['val']
344     assert cfg.val2 == ['val']
345     cfg.val1 = ['new-val']
346     assert cfg.val1 == ['new-val']
347     assert cfg.val2 == ['new-val']
348     cfg.val1.append('new-val2')
349     assert cfg.val1 == ['new-val', 'new-val2']
350     assert cfg.val2 == ['new-val', 'new-val2']
351     del(cfg.val1)
352     assert cfg.val1 == ['val']
353     assert cfg.val2 == ['val']
354
355
356 def test_callback_multi_list():
357     val1 = StrOption('val1', "", callback=return_list, multi=True)
358     maconfig = OptionDescription('rootconfig', '', [val1])
359     cfg = Config(maconfig)
360     cfg.read_write()
361     assert cfg.val1 == ['val', 'val']
362     cfg.val1 = ['new-val']
363     assert cfg.val1 == ['new-val']
364     cfg.val1.append('new-val2')
365     assert cfg.val1 == ['new-val', 'new-val2']
366     del(cfg.val1)
367     assert cfg.val1 == ['val', 'val']
368
369
370 def test_callback_master_and_slaves_master():
371     val1 = StrOption('val1', "", multi=True, callback=return_val)
372     val2 = StrOption('val2', "", multi=True)
373     interface1 = OptionDescription('val1', '', [val1, val2])
374     interface1.impl_set_group_type(groups.master)
375     maconfig = OptionDescription('rootconfig', '', [interface1])
376     cfg = Config(maconfig)
377     cfg.read_write()
378     assert cfg.val1.val1 == ['val']
379     cfg.val1.val1.append(None)
380     assert cfg.val1.val1 == ['val', 'val']
381     assert cfg.val1.val2 == [None, None]
382
383
384 def test_callback_master_and_slaves_master_list():
385     val1 = StrOption('val1', "", multi=True, callback=return_list)
386     val2 = StrOption('val2', "", multi=True)
387     interface1 = OptionDescription('val1', '', [val1, val2])
388     interface1.impl_set_group_type(groups.master)
389     maconfig = OptionDescription('rootconfig', '', [interface1])
390     cfg = Config(maconfig)
391     cfg.read_write()
392     assert cfg.val1.val1 == ['val', 'val']
393     assert cfg.val1.val2 == [None, None]
394     cfg.val1.val1.append(None)
395     assert cfg.val1.val1 == ['val', 'val', None]
396     assert cfg.val1.val2 == [None, None, None]
397     del(cfg.val1.val1)
398     assert cfg.val1.val1 == ['val', 'val']
399     assert cfg.val1.val2 == [None, None]
400     assert cfg.val1.val1.pop(1)
401     assert cfg.val1.val1 == ['val']
402     assert cfg.val1.val2 == [None]
403
404
405 def test_callback_master_and_slaves_slave():
406     val1 = StrOption('val1', "", multi=True)
407     val2 = StrOption('val2', "", multi=True, callback=return_val)
408     interface1 = OptionDescription('val1', '', [val1, val2])
409     interface1.impl_set_group_type(groups.master)
410     maconfig = OptionDescription('rootconfig', '', [interface1])
411     cfg = Config(maconfig)
412     cfg.read_write()
413     assert cfg.val1.val1 == []
414     assert cfg.val1.val2 == []
415     #
416     cfg.val1.val1 = ['val1']
417     assert cfg.val1.val1 == ['val1']
418     assert cfg.val1.val2 == ['val']
419     #
420     cfg.val1.val1.append('val2')
421     assert cfg.val1.val1 == ['val1', 'val2']
422     assert cfg.val1.val2 == ['val', 'val']
423     #
424     cfg.val1.val1 = ['val1', 'val2', 'val3']
425     assert cfg.val1.val1 == ['val1', 'val2', 'val3']
426     assert cfg.val1.val2 == ['val', 'val', 'val']
427     #
428     cfg.val1.val1.pop(2)
429     assert cfg.val1.val1 == ['val1', 'val2']
430     assert cfg.val1.val2 == ['val', 'val']
431     #
432     cfg.val1.val2 = ['val2', 'val2']
433     assert cfg.val1.val2 == ['val2', 'val2']
434     #
435     cfg.val1.val1.append('val3')
436     assert cfg.val1.val2 == ['val2', 'val2', 'val']
437
438
439 def test_callback_master_and_slaves_slave_list():
440     val1 = StrOption('val1', "", multi=True)
441     val2 = StrOption('val2', "", multi=True, callback=return_list)
442     interface1 = OptionDescription('val1', '', [val1, val2])
443     interface1.impl_set_group_type(groups.master)
444     maconfig = OptionDescription('rootconfig', '', [interface1])
445     cfg = Config(maconfig)
446     cfg.read_write()
447     assert cfg.val1.val2 == []
448     cfg.val1.val1 = ['val1', 'val2']
449     assert cfg.val1.val1 == ['val1', 'val2']
450     assert cfg.val1.val2 == ['val', 'val']
451     cfg.val1.val1 = ['val1']
452     #wrong len
453     raises(SlaveError, 'cfg.val1.val2')
454
455
456 def test_callback_master_and_slaves_value():
457     val1 = StrOption('val1', "", multi=True)
458     val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1.val1', False),)})
459     interface1 = OptionDescription('val1', '', [val1, val2])
460     interface1.impl_set_group_type(groups.master)
461     maconfig = OptionDescription('rootconfig', '', [interface1])
462     cfg = Config(maconfig)
463     cfg.read_write()
464     assert cfg.val1.val1 == []
465     assert cfg.val1.val2 == []
466     #
467     cfg.val1.val1 = ['val1']
468     assert cfg.val1.val1 == ['val1']
469     assert cfg.val1.val2 == ['val1']
470     #
471     cfg.val1.val1.append('val2')
472     assert cfg.val1.val1 == ['val1', 'val2']
473     assert cfg.val1.val2 == ['val1', 'val2']
474     #
475     cfg.val1.val1 = ['val1', 'val2', 'val3']
476     assert cfg.val1.val1 == ['val1', 'val2', 'val3']
477     assert cfg.val1.val2 == ['val1', 'val2', 'val3']
478     #
479     cfg.val1.val1.pop(2)
480     assert cfg.val1.val1 == ['val1', 'val2']
481     assert cfg.val1.val2 == ['val1', 'val2']
482     #
483     cfg.val1.val2 = ['val2', 'val2']
484     assert cfg.val1.val2 == ['val2', 'val2']
485     #
486     cfg.val1.val1.append('val3')
487     assert cfg.val1.val2 == ['val2', 'val2', 'val3']
488
489
490 def test_callback_hidden():
491     opt1 = BoolOption('opt1', '')
492     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)})
493     od1 = OptionDescription('od1', '', [opt1], properties=('hidden',))
494     od2 = OptionDescription('od2', '', [opt2])
495     maconfig = OptionDescription('rootconfig', '', [od1, od2])
496     cfg = Config(maconfig)
497     cfg.cfgimpl_get_settings().setpermissive(('hidden',))
498     cfg.read_write()
499     raises(PropertiesOptionError, 'cfg.od1.opt1')
500     cfg.od2.opt2
501
502
503 def test_callback_two_disabled():
504     opt1 = BoolOption('opt1', '', properties=('disabled',))
505     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}, properties=('disabled',))
506     od1 = OptionDescription('od1', '', [opt1])
507     od2 = OptionDescription('od2', '', [opt2])
508     maconfig = OptionDescription('rootconfig', '', [od1, od2])
509     cfg = Config(maconfig)
510     cfg.read_write()
511     raises(PropertiesOptionError, 'cfg.od2.opt2')
512
513
514 def test_callback_calculating_disabled():
515     opt1 = BoolOption('opt1', '', properties=('disabled',))
516     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)})
517     od1 = OptionDescription('od1', '', [opt1])
518     od2 = OptionDescription('od2', '', [opt2])
519     maconfig = OptionDescription('rootconfig', '', [od1, od2])
520     cfg = Config(maconfig)
521     cfg.read_write()
522     raises(ConfigError, 'cfg.od2.opt2')
523
524
525 def test_callback_calculating_mandatory():
526     opt1 = BoolOption('opt1', '', properties=('disabled',))
527     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}, properties=('mandatory',))
528     od1 = OptionDescription('od1', '', [opt1])
529     od2 = OptionDescription('od2', '', [opt2])
530     maconfig = OptionDescription('rootconfig', '', [od1, od2])
531     cfg = Config(maconfig)
532     cfg.read_only()
533     raises(ConfigError, 'cfg.od2.opt2')