consistency is now check not_equal if one option has PropertiesOptionError
[tiramisu.git] / test / test_option_calculation.py
1 from autopath import do_autopath
2 do_autopath()
3
4 from py.test import raises
5
6 from tiramisu.config import Config
7 from tiramisu.setting import groups, owners
8 from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
9     StrOption, OptionDescription, SymLinkOption, IPOption, NetmaskOption
10 from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError
11
12
13 def return_val():
14     return 'val'
15
16
17 def return_concat(*args):
18     return '.'.join(list(args))
19
20
21 def return_list(value=None):
22     return ['val', 'val']
23
24
25 def return_list2(*args):
26     l = []
27     for arg in args:
28         if isinstance(arg, list):
29             l.extend(arg)
30         else:
31             l.append(arg)
32     return l
33
34
35 def return_value(value=None):
36     return value
37
38
39 def return_value2(*args, **kwargs):
40     value = list(args)
41     value.extend(kwargs.values())
42     return value
43
44
45 def return_calc(i, j, k):
46     return i + j + k
47
48
49 def is_config(config, **kwargs):
50     if isinstance(config, Config):
51         return 'yes'
52     else:
53         return 'no'
54
55
56 def make_description_duplicates():
57     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
58     ## dummy 1
59     gcdummy = BoolOption('dummy', 'dummy', default=False)
60     objspaceoption = ChoiceOption('objspace', 'Object space',
61                                   ('std', 'thunk'), 'std')
62     booloption = BoolOption('bool', 'Test boolean option', default=True)
63     intoption = IntOption('int', 'Test int option', default=0)
64     floatoption = FloatOption('float', 'Test float option', default=2.3)
65     stroption = StrOption('str', 'Test string option', default="abc")
66     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
67     wantref_option = BoolOption('wantref', 'Test requires', default=False,
68                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
69     wantframework_option = BoolOption('wantframework', 'Test requires',
70                                       default=False,
71                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
72     # dummy2 (same path)
73     gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
74     # dummy3 (same name)
75     gcdummy3 = BoolOption('dummy', 'dummy2', default=True)
76     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, gcdummy2, floatoption])
77     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
78                               wantref_option, stroption,
79                               wantframework_option,
80                               intoption, boolop, gcdummy3])
81     return descr
82
83
84 def test_identical_paths():
85     """If in the schema (the option description) there is something that
86     have the same name, an exection is raised
87     """
88     raises(ConflictError, "make_description_duplicates()")
89
90
91 def make_description_requires():
92     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
93     gcdummy = BoolOption('dummy', 'dummy', default=False)
94
95     floatoption = FloatOption('float', 'Test float option', default=2.3)
96
97     objspaceoption = ChoiceOption('objspace', 'Object space',
98                                   ('std', 'thunk'), 'std')
99     booloption = BoolOption('bool', 'Test boolean option', default=True)
100     intoption = IntOption('int', 'Test int option', default=0)
101     stroption = StrOption('str', 'Test string option', default="abc",
102                           requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},))
103
104     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
105     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
106                               stroption, intoption])
107     return descr
108
109
110 def test_hidden_if_in():
111     descr = make_description_requires()
112     cfg = Config(descr)
113     setting = cfg.cfgimpl_get_settings()
114     cfg.read_write()
115     stroption = cfg.unwrap_from_path('str')
116     assert not 'hidden' in setting[stroption]
117     cfg.int = 1
118     raises(PropertiesOptionError, "cfg.str")
119     raises(PropertiesOptionError, 'cfg.str="uvw"')
120     assert 'hidden' in setting[stroption]
121
122
123 def test_hidden_if_in_with_group():
124     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
125     gcdummy = BoolOption('dummy', 'dummy', default=False)
126
127     floatoption = FloatOption('float', 'Test float option', default=2.3)
128
129     objspaceoption = ChoiceOption('objspace', 'Object space',
130                                   ('std', 'thunk'), 'std')
131     booloption = BoolOption('bool', 'Test boolean option', default=True)
132     intoption = IntOption('int', 'Test int option', default=0)
133     stroption = StrOption('str', 'Test string option', default="abc")
134     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
135                                 requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},))
136     descr = OptionDescription('constraints', '', [gcgroup, booloption,
137                               objspaceoption, stroption, intoption])
138     cfg = Config(descr)
139     setting = cfg.cfgimpl_get_settings()
140     cfg.read_write()
141     assert not 'hidden' in setting[stroption]
142     cfg.int = 1
143     raises(PropertiesOptionError, "cfg.gc.name")
144
145
146 def test_disabled_with_group():
147     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
148     gcdummy = BoolOption('dummy', 'dummy', default=False)
149
150     floatoption = FloatOption('float', 'Test float option', default=2.3)
151
152     objspaceoption = ChoiceOption('objspace', 'Object space',
153                                   ('std', 'thunk'), 'std')
154     booloption = BoolOption('bool', 'Test boolean option', default=True)
155     intoption = IntOption('int', 'Test int option', default=0)
156     stroption = StrOption('str', 'Test string option', default="abc")
157     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
158                                 requires=({'option': intoption, 'expected': 1, 'action': 'disabled'},))
159     descr = OptionDescription('constraints', '', [gcgroup, booloption,
160                               objspaceoption, stroption, intoption])
161     cfg = Config(descr)
162     cfg.read_write()
163     assert cfg.gc.name
164     cfg.int = 1
165     raises(PropertiesOptionError, "cfg.gc.name")
166 #____________________________________________________________
167
168
169 def make_description_callback():
170     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
171     gcdummy = BoolOption('dummy', 'dummy')
172     objspaceoption = ChoiceOption('objspace', 'Object space',
173                                   ('std', 'thunk'), 'std')
174     booloption = BoolOption('bool', 'Test boolean option', default=True)
175     intoption = IntOption('int', 'Test int option', default=0)
176     floatoption = FloatOption('float', 'Test float option', default=2.3)
177     stroption = StrOption('str', 'Test string option', default="abc")
178     boolop = BoolOption('boolop', 'Test boolean option op', default=True)
179     wantref_option = BoolOption('wantref', 'Test requires', default=False,
180                                 requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
181     wantframework_option = BoolOption('wantframework', 'Test requires',
182                                       default=False,
183                                       requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
184     gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
185     descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
186                               wantref_option, stroption,
187                               wantframework_option,
188                               intoption, boolop])
189     return descr
190
191
192 def test_has_callback():
193     descr = make_description_callback()
194     # here the owner is 'default'
195     config = Config(descr)
196     setting = config.cfgimpl_get_settings()
197     config.read_write()
198     config.bool = False
199     # because dummy has a callback
200     dummy = config.unwrap_from_path('gc.dummy')
201     setting.append('freeze')
202     setting[dummy].append('frozen')
203     raises(PropertiesOptionError, "config.gc.dummy = True")
204
205
206 def test_freeze_and_has_callback():
207     descr = make_description_callback()
208     config = Config(descr)
209     setting = config.cfgimpl_get_settings()
210     config.read_write()
211     config.bool = False
212     setting = config.cfgimpl_get_settings()
213     setting.append('freeze')
214     dummy = config.unwrap_from_path('gc.dummy')
215     setting[dummy].append('frozen')
216     raises(PropertiesOptionError, "config.gc.dummy = True")
217
218
219 def test_callback():
220     val1 = StrOption('val1', "", callback=return_val)
221     maconfig = OptionDescription('rootconfig', '', [val1])
222     cfg = Config(maconfig)
223     cfg.read_write()
224     assert cfg.val1 == 'val'
225     cfg.val1 = 'new-val'
226     assert cfg.val1 == 'new-val'
227     del(cfg.val1)
228     assert cfg.val1 == 'val'
229
230
231 def test_callback_params_without_callback():
232     raises(ValueError, "StrOption('val2', '', callback_params={'': ('yes',)})")
233
234
235 def test_callback_invalid():
236     raises(ValueError, 'val1 = StrOption("val1", "", callback="string")')
237     raises(ValueError, 'val1 = StrOption("val1", "", callback=return_val, callback_params="string")')
238     val1 = StrOption('val1', "", 'val')
239     val1
240     raises(ValueError, "StrOption('val2', '', callback=return_value, callback_params={'': 'string'})")
241     raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': (('string', False),)})")
242     raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, 'string'),)})")
243     raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, False, 'unknown'),)})")
244     raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1,),)})")
245
246
247 def test_callback_with_context():
248     val1 = StrOption("val1", "", callback=is_config, callback_params={'': ((None,),), 'value': ('string',)})
249     maconfig = OptionDescription('rootconfig', '', [val1])
250     cfg = Config(maconfig)
251     assert cfg.val1 == 'yes'
252
253
254 def test_callback_with_context_named():
255     val1 = StrOption("val1", "", callback=is_config, callback_params={'config': ((None,),)})
256     maconfig = OptionDescription('rootconfig', '', [val1])
257     cfg = Config(maconfig)
258     assert cfg.val1 == 'yes'
259
260
261 def test_callback_with_error():
262     val1 = StrOption("val1", "", callback=is_config, callback_params={'': ('string',), 'value': ('string',)})
263     maconfig = OptionDescription('rootconfig', '', [val1])
264     cfg = Config(maconfig)
265     assert cfg.val1 == 'no'
266
267
268 def test_callback_value():
269     val1 = StrOption('val1', "", 'val')
270     val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
271     val3 = StrOption('val3', "", callback=return_value, callback_params={'': ('yes',)})
272     val4 = StrOption('val4', "", callback=return_value, callback_params={'value': ((val1, False),)})
273     val5 = StrOption('val5', "", callback=return_value, callback_params={'value': ('yes',)})
274     maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
275     cfg = Config(maconfig)
276     cfg.read_write()
277     assert cfg.val1 == 'val'
278     assert cfg.val2 == 'val'
279     assert cfg.val4 == 'val'
280     cfg.val1 = 'new-val'
281     assert cfg.val1 == 'new-val'
282     assert cfg.val2 == 'new-val'
283     assert cfg.val4 == 'new-val'
284     del(cfg.val1)
285     assert cfg.val1 == 'val'
286     assert cfg.val2 == 'val'
287     assert cfg.val3 == 'yes'
288     assert cfg.val4 == 'val'
289     assert cfg.val5 == 'yes'
290
291
292 def test_callback_value_tuple():
293     val1 = StrOption('val1', "", 'val1')
294     val2 = StrOption('val2', "", 'val2')
295     val3 = StrOption('val3', "", callback=return_concat, callback_params={'': ((val1, False), (val2, False))})
296     val4 = StrOption('val4', "", callback=return_concat, callback_params={'': ('yes', 'no')})
297     raises(ValueError, "StrOption('val4', '', callback=return_concat, callback_params={'value': ('yes', 'no')})")
298     maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4])
299     cfg = Config(maconfig)
300     cfg.read_write()
301     assert cfg.val1 == 'val1'
302     assert cfg.val2 == 'val2'
303     assert cfg.val3 == 'val1.val2'
304     assert cfg.val4 == 'yes.no'
305     cfg.val1 = 'new-val'
306     assert cfg.val3 == 'new-val.val2'
307     del(cfg.val1)
308     assert cfg.val3 == 'val1.val2'
309
310
311 def test_callback_value_force_permissive():
312     val1 = StrOption('val1', "", 'val', properties=('disabled',))
313     val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
314     val3 = StrOption('val3', "", callback=return_value, callback_params={'': ((val1, True),)})
315     maconfig = OptionDescription('rootconfig', '', [val1, val2, val3])
316     cfg = Config(maconfig)
317     cfg.read_only()
318     raises(ConfigError, "cfg.val2")
319     assert cfg.val3 is None
320
321
322 def test_callback_symlink():
323     val1 = StrOption('val1', "", 'val')
324     val2 = SymLinkOption('val2', val1)
325     val3 = StrOption('val3', "", callback=return_value, callback_params={'': ((val2, False),)})
326     maconfig = OptionDescription('rootconfig', '', [val1, val2, val3])
327     cfg = Config(maconfig)
328     cfg.read_write()
329     assert cfg.val1 == 'val'
330     assert cfg.val2 == 'val'
331     assert cfg.val3 == 'val'
332     cfg.val1 = 'new-val'
333     assert cfg.val1 == 'new-val'
334     assert cfg.val3 == 'new-val'
335     del(cfg.val1)
336     assert cfg.val1 == 'val'
337     assert cfg.val3 == 'val'
338
339
340 def test_callback_list():
341     val1 = StrOption('val1', "", callback=return_list)
342     maconfig = OptionDescription('rootconfig', '', [val1])
343     cfg = Config(maconfig)
344     cfg.read_write()
345     raises(ValueError, "cfg.val1")
346
347
348 def test_callback_multi():
349     val1 = StrOption('val1', "", callback=return_val, multi=True)
350     maconfig = OptionDescription('rootconfig', '', [val1])
351     cfg = Config(maconfig)
352     cfg.read_write()
353     assert cfg.val1 == ['val']
354     cfg.val1 = ['new-val']
355     assert cfg.val1 == ['new-val']
356     cfg.val1.append('new-val2')
357     assert cfg.val1 == ['new-val', 'new-val2']
358     del(cfg.val1)
359     assert cfg.val1 == ['val']
360
361
362 def test_callback_multi_value():
363     val1 = StrOption('val1', "", ['val'], multi=True)
364     val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
365     val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
366     val4 = StrOption('val4', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), 'yes')})
367     maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4])
368     cfg = Config(maconfig)
369     cfg.read_write()
370     assert cfg.val1 == ['val']
371     assert cfg.val2 == ['val']
372     assert cfg.val4 == ['val', 'yes']
373     cfg.val1 = ['new-val']
374     assert cfg.val1 == ['new-val']
375     assert cfg.val2 == ['new-val']
376     assert cfg.val4 == ['new-val', 'yes']
377     cfg.val1.append('new-val2')
378     assert cfg.val1 == ['new-val', 'new-val2']
379     assert cfg.val2 == ['new-val', 'new-val2']
380     assert cfg.val4 == ['new-val', 'new-val2', 'yes']
381     del(cfg.val1)
382     assert cfg.val1 == ['val']
383     assert cfg.val2 == ['val']
384     assert cfg.val3 == ['yes']
385     assert cfg.val4 == ['val', 'yes']
386     cfg.val2.append('new')
387     assert cfg.val1 == ['val']
388     assert cfg.val2 == ['val', 'new']
389
390
391 def test_callback_multi_list():
392     val1 = StrOption('val1', "", callback=return_list, multi=True)
393     maconfig = OptionDescription('rootconfig', '', [val1])
394     cfg = Config(maconfig)
395     cfg.read_write()
396     assert cfg.val1 == ['val', 'val']
397     cfg.val1 = ['new-val']
398     assert cfg.val1 == ['new-val']
399     cfg.val1.append('new-val2')
400     assert cfg.val1 == ['new-val', 'new-val2']
401     del(cfg.val1)
402     assert cfg.val1 == ['val', 'val']
403
404
405 def test_callback_multi_list_extend():
406     val1 = StrOption('val1', "", callback=return_list2, callback_params={'': (['1', '2', '3'], ['4', '5'])}, multi=True)
407     maconfig = OptionDescription('rootconfig', '', [val1])
408     cfg = Config(maconfig)
409     cfg.read_write()
410     assert cfg.val1 == ['1', '2', '3', '4', '5']
411
412
413 def test_callback_multi_callback():
414     val1 = StrOption('val1', "", multi=True, callback=return_val)
415     interface1 = OptionDescription('val1', '', [val1])
416     maconfig = OptionDescription('rootconfig', '', [interface1])
417     cfg = Config(maconfig)
418     cfg.read_write()
419     assert cfg.val1.val1 == ['val']
420     cfg.val1.val1 = ['val1']
421     cfg.val1.val1.append()
422     assert cfg.val1.val1 == ['val1', 'val']
423
424
425 def test_callback_master_and_slaves_master():
426     val1 = StrOption('val1', "", multi=True, callback=return_val)
427     val2 = StrOption('val2', "", multi=True)
428     interface1 = OptionDescription('val1', '', [val1, val2])
429     interface1.impl_set_group_type(groups.master)
430     maconfig = OptionDescription('rootconfig', '', [interface1])
431     cfg = Config(maconfig)
432     cfg.read_write()
433     assert cfg.val1.val1 == ['val']
434     cfg.val1.val1.append()
435     assert cfg.val1.val1 == ['val', 'val']
436     assert cfg.val1.val2 == [None, None]
437
438
439 def test_callback_master_and_slaves_master2():
440     val1 = StrOption('val1', "", multi=True)
441     val2 = StrOption('val2', "", multi=True, default_multi='val2')
442     val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
443     val4 = StrOption('val4', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
444     interface1 = OptionDescription('val1', '', [val1, val2, val3, val4])
445     interface1.impl_set_group_type(groups.master)
446     maconfig = OptionDescription('rootconfig', '', [interface1])
447     cfg = Config(maconfig)
448     cfg.read_write()
449     cfg.val1.val1.append('val')
450     assert cfg.val1.val4 == ['val2']
451     assert cfg.val1.val3 == ['val2']
452     assert cfg.val1.val2 == ['val2']
453
454
455 def test_callback_master_and_slaves_master3():
456     val1 = StrOption('val1', "", multi=True, properties=('mandatory', 'empty'))
457     val2 = StrOption('val2', "", multi=True, default_multi='val2', properties=('expert',))
458     val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
459     val4 = StrOption('val4', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
460     interface1 = OptionDescription('val1', '', [val1, val2, val3, val4])
461     interface1.impl_set_group_type(groups.master)
462     maconfig = OptionDescription('rootconfig', '', [interface1])
463     cfg = Config(maconfig)
464     cfg.read_write()
465     assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ['val1.val1']
466
467
468 def test_callback_master_and_slaves_master4():
469     val1 = StrOption('val1', "", ['val1'], multi=True, properties=('mandatory',))
470     val2 = StrOption('val2', "", multi=True, default_multi='val2', properties=('expert', 'mandatory'))
471     val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
472     val4 = StrOption('val4', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
473     interface1 = OptionDescription('val1', '', [val1, val2, val3, val4])
474     interface1.impl_set_group_type(groups.master)
475     maconfig = OptionDescription('rootconfig', '', [interface1])
476     cfg = Config(maconfig)
477     cfg.read_write()
478     cfg.cfgimpl_get_settings().append('expert')
479     cfg.cfgimpl_get_settings().setpermissive(('expert',))
480     assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == []
481
482
483 def test_consistency_master_and_slaves_master_mandatory_transitive():
484     #default value
485     val1 = IPOption('val1', "", ['192.168.0.1'], multi=True, properties=('mandatory',))
486     val2 = NetmaskOption('val2', "", multi=True, default_multi='255.255.255.0', properties=('disabled', 'mandatory'))
487     val2.impl_add_consistency('ip_netmask', val1)
488     #no value
489     val3 = IPOption('val3', "", multi=True, properties=('mandatory',))
490     val4 = NetmaskOption('val4', "", multi=True, default_multi='255.255.255.0', properties=('disabled', 'mandatory'))
491     val4.impl_add_consistency('ip_netmask', val3)
492     interface1 = OptionDescription('val1', '', [val1, val2])
493     interface2 = OptionDescription('val3', '', [val3, val4])
494     interface1.impl_set_group_type(groups.master)
495     interface2.impl_set_group_type(groups.master)
496     maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
497     cfg = Config(maconfig)
498     cfg.read_write()
499     raises(PropertiesOptionError, "cfg.val1.val1")
500     raises(PropertiesOptionError, "cfg.val3.val3")
501     assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == []
502
503
504 def test_consistency_master_and_slaves_master_mandatory_non_transitive():
505     #no value
506     val1 = IPOption('val1', "", multi=True, properties=('mandatory',))
507     val2 = NetmaskOption('val2', "", multi=True, default_multi='255.255.255.0', properties=('disabled', 'mandatory'))
508     val2.impl_add_consistency('ip_netmask', val1, transitive=False)
509     #default value
510     val3 = IPOption('val3', "", ['192.168.0.1'], multi=True, properties=('mandatory',))
511     val4 = NetmaskOption('val4', "", multi=True, default_multi='255.255.255.0', properties=('disabled', 'mandatory'))
512     val4.impl_add_consistency('ip_netmask', val3, transitive=False)
513     interface1 = OptionDescription('val1', '', [val1, val2])
514     interface2 = OptionDescription('val3', '', [val3, val4])
515     interface1.impl_set_group_type(groups.master)
516     interface2.impl_set_group_type(groups.master)
517     maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
518     cfg = Config(maconfig)
519     cfg.read_write()
520     assert list(cfg.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ["val1.val1"]
521
522
523 def test_callback_master_and_slaves_master_list():
524     val1 = StrOption('val1', "", multi=True, callback=return_list)
525     val2 = StrOption('val2', "", multi=True)
526     interface1 = OptionDescription('val1', '', [val1, val2])
527     interface1.impl_set_group_type(groups.master)
528     maconfig = OptionDescription('rootconfig', '', [interface1])
529     cfg = Config(maconfig)
530     cfg.read_write()
531     assert cfg.val1.val1 == ['val', 'val']
532     assert cfg.val1.val2 == [None, None]
533     cfg.val1.val1.append()
534     assert cfg.val1.val1 == ['val', 'val', None]
535     assert cfg.val1.val2 == [None, None, None]
536     del(cfg.val1.val1)
537     assert cfg.val1.val1 == ['val', 'val']
538     assert cfg.val1.val2 == [None, None]
539     assert cfg.val1.val1.pop(1)
540     assert cfg.val1.val1 == ['val']
541     assert cfg.val1.val2 == [None]
542
543
544 def test_callback_master_and_slaves_slave():
545     val1 = StrOption('val1', "", multi=True)
546     val2 = StrOption('val2', "", multi=True, callback=return_val)
547     interface1 = OptionDescription('val1', '', [val1, val2])
548     interface1.impl_set_group_type(groups.master)
549     maconfig = OptionDescription('rootconfig', '', [interface1])
550     cfg = Config(maconfig)
551     cfg.read_write()
552     assert cfg.val1.val1 == []
553     assert cfg.val1.val2 == []
554     #
555     cfg.val1.val1 = ['val1']
556     assert cfg.val1.val1 == ['val1']
557     assert cfg.val1.val2 == ['val']
558     #
559     cfg.val1.val1.append('val2')
560     assert cfg.val1.val1 == ['val1', 'val2']
561     assert cfg.val1.val2 == ['val', 'val']
562     #
563     cfg.val1.val1 = ['val1', 'val2', 'val3']
564     assert cfg.val1.val1 == ['val1', 'val2', 'val3']
565     assert cfg.val1.val2 == ['val', 'val', 'val']
566     #
567     cfg.val1.val1.pop(2)
568     assert cfg.val1.val1 == ['val1', 'val2']
569     assert cfg.val1.val2 == ['val', 'val']
570     #
571     cfg.val1.val2 = ['val2', 'val2']
572     assert cfg.val1.val2 == ['val2', 'val2']
573     #
574     cfg.val1.val1.append('val3')
575     assert cfg.val1.val2 == ['val2', 'val2', 'val']
576
577
578 def test_callback_master_and_slaves():
579     val1 = StrOption('val1', "", multi=True)
580     val2 = StrOption('val2', "", multi=True, callback=return_val)
581     interface1 = OptionDescription('val1', '', [val1, val2])
582     interface1.impl_set_group_type(groups.master)
583     maconfig = OptionDescription('rootconfig', '', [interface1])
584     cfg = Config(maconfig)
585     cfg.read_write()
586
587
588 def test_callback_master_and_slaves_slave_cal():
589     val3 = StrOption('val3', "", multi=True)
590     val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
591     val2 = StrOption('val2', "", multi=True, callback=return_val)
592     interface1 = OptionDescription('val1', '', [val1, val2])
593     interface1.impl_set_group_type(groups.master)
594     maconfig = OptionDescription('rootconfig', '', [interface1, val3])
595     cfg = Config(maconfig)
596     cfg.read_write()
597     assert cfg.val3 == []
598     assert cfg.val1.val1 == []
599     assert cfg.val1.val2 == []
600     cfg.val1.val1 = ['val1']
601     cfg.val3 = ['val1']
602     assert cfg.val1.val1 == ['val1']
603     assert cfg.val1.val2 == ['val']
604     del(cfg.val1.val1)
605     cfg.val1.val2 = ['val']
606     cfg.val3 = ['val1', 'val2']
607     assert cfg.val1.val2 == ['val', 'val']
608     assert cfg.val1.val1 == ['val1', 'val2']
609     cfg.val1.val2 = ['val1', 'val2']
610     cfg.val3.pop(1)
611     # cannot remove slave's value because master is calculated
612     # so raise
613     raises(SlaveError, "cfg.val1.val1")
614     raises(SlaveError, "cfg.val1.val2")
615     cfg.val3 = ['val1', 'val2', 'val3']
616     assert cfg.val1.val2 == ['val1', 'val2', 'val']
617
618
619 def test_callback_master_and_slaves_master_disabled():
620     #properties must be transitive
621     val1 = StrOption('val1', "", multi=True, properties=('disabled',))
622     val2 = StrOption('val2', "", multi=True)
623     interface1 = OptionDescription('val1', '', [val1, val2])
624     interface1.impl_set_group_type(groups.master)
625     maconfig = OptionDescription('rootconfig', '', [interface1])
626     cfg = Config(maconfig)
627     cfg.read_write()
628     raises(PropertiesOptionError, "cfg.val1.val1")
629     raises(PropertiesOptionError, "cfg.val1.val1.append('yes')")
630     raises(PropertiesOptionError, "cfg.val1.val2")
631
632
633 def test_callback_master_and_slaves_master_callback_disabled():
634     val0 = StrOption('val0', "", multi=True, properties=('disabled',))
635     val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val0, False),)})
636     val2 = StrOption('val2', "", multi=True)
637     interface1 = OptionDescription('val1', '', [val1, val2])
638     interface1.impl_set_group_type(groups.master)
639     maconfig = OptionDescription('rootconfig', '', [interface1, val0])
640     cfg = Config(maconfig)
641     cfg.read_write()
642     raises(ConfigError, "cfg.val1.val1")
643     raises(ConfigError, "cfg.val1.val2")
644     cfg.cfgimpl_get_settings().remove('disabled')
645     cfg.val1.val1 = []
646     cfg.cfgimpl_get_settings().append('disabled')
647     assert cfg.val1.val1 == []
648     assert cfg.val1.val2 == []
649
650
651 def test_callback_master_and_slaves_slave_disabled():
652     val1 = StrOption('val1', "", multi=True)
653     val2 = StrOption('val2', "", multi=True, properties=('disabled',))
654     interface1 = OptionDescription('val1', '', [val1, val2])
655     interface1.impl_set_group_type(groups.master)
656     maconfig = OptionDescription('rootconfig', '', [interface1])
657     cfg = Config(maconfig)
658     cfg.read_write()
659     assert cfg.val1.val1 == []
660     raises(PropertiesOptionError, "cfg.val1.val2")
661     cfg.val1.val1.append('yes')
662     assert cfg.val1.val1 == ['yes']
663     cfg.cfgimpl_get_settings().remove('disabled')
664     assert cfg.val1.val2 == [None]
665     cfg.val1.val2 = ['no']
666     cfg.val1.val1.append('yes2')
667     cfg.val1.val1.append('yes3')
668     cfg.val1.val2[2] = 'no1'
669     assert cfg.val1.val2 == ['no', None, 'no1']
670     cfg.cfgimpl_get_settings().append('disabled')
671     cfg.val1.val1.pop(0)
672     assert cfg.val1.val1 == ['yes2', 'yes3']
673     cfg.cfgimpl_get_settings().remove('disabled')
674     assert cfg.val1.val2 == [None, 'no1']
675
676
677 def test_callback_master_and_slaves_slave_callback_disabled():
678     val0 = StrOption('val0', "", multi=True, properties=('disabled',))
679     val1 = StrOption('val1', "", multi=True)
680     val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val0, False),)})
681     interface1 = OptionDescription('val1', '', [val1, val2])
682     interface1.impl_set_group_type(groups.master)
683     maconfig = OptionDescription('rootconfig', '', [interface1, val0])
684     cfg = Config(maconfig)
685     cfg.read_write()
686     assert cfg.val1.val1 == []
687     assert cfg.val1.val2 == []
688     cfg.val1.val1.append('yes')
689     assert cfg.val1.val1 == ['yes']
690     cfg.cfgimpl_get_settings().remove('disabled')
691     raises(SlaveError, "cfg.val1.val2")
692     cfg.val1.val2 = ['no']
693     cfg.val1.val1.append('yes1')
694     raises(SlaveError, "cfg.val1.val2")
695     cfg.cfgimpl_get_settings().append('disabled')
696     raises(ConfigError, "cfg.val1.val1.pop(0)")
697
698
699 def test_callback_master_and_slaves_value():
700     val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
701     val1 = StrOption('val1', "", multi=True)
702     val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
703     val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
704     val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)})
705     val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val5, False),)})
706     interface1 = OptionDescription('val1', '', [val1, val2, val3, val5, val6])
707     interface1.impl_set_group_type(groups.master)
708     maconfig = OptionDescription('rootconfig', '', [interface1, val4])
709     cfg = Config(maconfig)
710     cfg.read_write()
711     cfg.val4 == ['val10', 'val11']
712     assert cfg.val1.val1 == []
713     assert cfg.val1.val2 == []
714     assert cfg.val1.val3 == []
715     assert cfg.val1.val5 == []
716     assert cfg.val1.val6 == []
717     #raises(SlaveError, "cfg.val1.val1")
718     #raises(SlaveError, "cfg.val1.val2")
719     #raises(SlaveError, "cfg.val1.val3")
720     #raises(SlaveError, "cfg.val1.val5")
721     #raises(SlaveError, "cfg.val1.val6")
722     #
723     #default calculation has greater length
724     #raises(SlaveError, "cfg.val1.val1 = ['val1']")
725     #
726     cfg.val1.val1 = ['val1', 'val2']
727     assert cfg.val1.val1 == ['val1', 'val2']
728     assert cfg.val1.val2 == ['val1', 'val2']
729     assert cfg.val1.val3 == ['yes', 'yes']
730     raises(SlaveError, "cfg.val1.val5")
731     raises(SlaveError, "cfg.val1.val6")
732     #
733     cfg.val1.val1.append('val3')
734     assert cfg.val1.val1 == ['val1', 'val2', 'val3']
735     assert cfg.val1.val2 == ['val1', 'val2', 'val3']
736     assert cfg.val1.val3 == ['yes', 'yes', 'yes']
737     raises(SlaveError, "cfg.val1.val5")
738     raises(SlaveError, "cfg.val1.val6")
739     #
740     cfg.val1.val1.pop(2)
741     assert cfg.val1.val1 == ['val1', 'val2']
742     assert cfg.val1.val2 == ['val1', 'val2']
743     assert cfg.val1.val3 == ['yes', 'yes']
744     raises(SlaveError, "cfg.val1.val5")
745     raises(SlaveError, "cfg.val1.val6")
746     #
747     cfg.val1.val2 = ['val2', 'val2']
748     cfg.val1.val3 = ['val2', 'val2']
749     cfg.val1.val5 = ['val2', 'val2']
750     assert cfg.val1.val2 == ['val2', 'val2']
751     assert cfg.val1.val3 == ['val2', 'val2']
752     assert cfg.val1.val5 == ['val2', 'val2']
753     assert cfg.val1.val6 == ['val2', 'val2']
754     #
755     cfg.val1.val1.append('val3')
756     assert cfg.val1.val2 == ['val2', 'val2', 'val3']
757     assert cfg.val1.val3 == ['val2', 'val2', 'yes']
758     raises(SlaveError, "cfg.val1.val5")
759     raises(SlaveError, "cfg.val1.val6")
760     cfg.cfgimpl_get_settings().remove('cache')
761     cfg.val4 = ['val10', 'val11', 'val12']
762     #if value is already set, not updated !
763     cfg.val1.val1.pop(2)
764     cfg.val1.val1.append('val3')
765     cfg.val1.val1 = ['val1', 'val2', 'val3']
766     raises(SlaveError, "cfg.val1.val5")
767     raises(SlaveError, "cfg.val1.val6")
768
769
770 def test_callback_master():
771     val2 = StrOption('val2', "", multi=True, callback=return_value)
772     val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
773     interface1 = OptionDescription('val1', '', [val1, val2])
774     interface1
775     raises(ValueError, "interface1.impl_set_group_type(groups.master)")
776
777
778 #FIXME: slave est un symlink
779
780
781 def test_callback_different_type():
782     val = IntOption('val', "", default=2)
783     val_ = IntOption('val_', "", default=3)
784     val1 = IntOption('val1', "", multi=True)
785     val2 = IntOption('val2', "", multi=True, callback=return_calc, callback_params={'': ((val, False), (val1, False)), 'k': ((val_, False),)})
786     interface1 = OptionDescription('val1', '', [val1, val2])
787     interface1.impl_set_group_type(groups.master)
788     maconfig = OptionDescription('rootconfig', '', [interface1, val, val_])
789     cfg = Config(maconfig)
790     cfg.read_write()
791     assert cfg.val1.val1 == []
792     assert cfg.val1.val2 == []
793     cfg.val1.val1 = [1]
794     assert cfg.val1.val1 == [1]
795     assert cfg.val1.val2 == [6]
796     cfg.val1.val1 = [1, 3]
797     assert cfg.val1.val1 == [1, 3]
798     assert cfg.val1.val2 == [6, 8]
799     cfg.val1.val1 = [1, 3, 5]
800     assert cfg.val1.val1 == [1, 3, 5]
801     assert cfg.val1.val2 == [6, 8, 10]
802
803
804 def test_callback_hidden():
805     opt1 = BoolOption('opt1', '')
806     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)})
807     od1 = OptionDescription('od1', '', [opt1], properties=('hidden',))
808     od2 = OptionDescription('od2', '', [opt2])
809     maconfig = OptionDescription('rootconfig', '', [od1, od2])
810     cfg = Config(maconfig)
811     cfg.cfgimpl_get_settings().setpermissive(('hidden',))
812     cfg.read_write()
813     raises(PropertiesOptionError, 'cfg.od1.opt1')
814     cfg.od2.opt2
815
816
817 def test_callback_two_disabled():
818     opt1 = BoolOption('opt1', '', properties=('disabled',))
819     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('disabled',))
820     od1 = OptionDescription('od1', '', [opt1])
821     od2 = OptionDescription('od2', '', [opt2])
822     maconfig = OptionDescription('rootconfig', '', [od1, od2])
823     cfg = Config(maconfig)
824     cfg.read_write()
825     raises(PropertiesOptionError, 'cfg.od2.opt2')
826
827
828 def test_callback_two_disabled2():
829     opt1 = BoolOption('opt1', '', properties=('hidden',))
830     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('hidden',))
831     od1 = OptionDescription('od1', '', [opt1])
832     od2 = OptionDescription('od2', '', [opt2])
833     maconfig = OptionDescription('rootconfig', '', [od1, od2])
834     cfg = Config(maconfig)
835     cfg.read_write()
836     cfg.cfgimpl_get_settings().setpermissive(('hidden',))
837     raises(PropertiesOptionError, 'cfg.od2.opt2')
838     assert cfg.getowner(opt2, force_permissive=True) == owners.default
839
840
841 def test_callback_calculating_invalid():
842     opt1 = IntOption('opt1', '', 1)
843     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)})
844     od1 = OptionDescription('od1', '', [opt1])
845     od2 = OptionDescription('od2', '', [opt2])
846     maconfig = OptionDescription('rootconfig', '', [od1, od2])
847     cfg = Config(maconfig)
848     setting = cfg.cfgimpl_get_settings()
849     cfg.read_write()
850     raises(ValueError, 'cfg.od2.opt2')
851     setting[opt2].append('disabled')
852     raises(PropertiesOptionError, 'cfg.od2.opt2')
853
854
855 def test_callback_calculating_disabled():
856     opt1 = BoolOption('opt1', '', properties=('disabled',))
857     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)})
858     od1 = OptionDescription('od1', '', [opt1])
859     od2 = OptionDescription('od2', '', [opt2])
860     maconfig = OptionDescription('rootconfig', '', [od1, od2])
861     cfg = Config(maconfig)
862     cfg.read_write()
863     raises(ConfigError, 'cfg.od2.opt2')
864
865
866 def test_callback_calculating_mandatory():
867     opt1 = BoolOption('opt1', '', properties=('disabled',))
868     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('mandatory',))
869     od1 = OptionDescription('od1', '', [opt1])
870     od2 = OptionDescription('od2', '', [opt2])
871     maconfig = OptionDescription('rootconfig', '', [od1, od2])
872     cfg = Config(maconfig)
873     cfg.read_only()
874     raises(ConfigError, 'cfg.od2.opt2')
875
876
877 def test_callback_calculating_mandatory_multi():
878     opt1 = BoolOption('opt1', '', multi=True, properties=('disabled',))
879     opt2 = BoolOption('opt2', '', multi=True, callback=return_value, callback_params={'': ((opt1, False),)}, properties=('mandatory',))
880     od1 = OptionDescription('od1', '', [opt1])
881     od2 = OptionDescription('od2', '', [opt2])
882     maconfig = OptionDescription('rootconfig', '', [od1, od2])
883     cfg = Config(maconfig)
884     cfg.read_only()
885     raises(ConfigError, 'cfg.od2.opt2')
886
887
888 def test_callback_two_disabled_multi():
889     opt1 = BoolOption('opt1', '', properties=('disabled',))
890     opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('disabled',), multi=True)
891     od1 = OptionDescription('od1', '', [opt1])
892     od2 = OptionDescription('od2', '', [opt2])
893     maconfig = OptionDescription('rootconfig', '', [od1, od2])
894     cfg = Config(maconfig)
895     cfg.read_write()
896     raises(PropertiesOptionError, 'cfg.od2.opt2')
897
898
899 def test_callback_multi_list_params():
900     val1 = StrOption('val1', "", multi=True, default=['val1', 'val2'])
901     val2 = StrOption('val2', "", multi=True, callback=return_list, callback_params={'': ((val1, False),)})
902     oval2 = OptionDescription('val2', '', [val2])
903     maconfig = OptionDescription('rootconfig', '', [val1, oval2])
904     cfg = Config(maconfig)
905     cfg.read_write()
906     assert cfg.val2.val2 == ['val', 'val']
907
908
909 def test_callback_multi_list_params_key():
910     val1 = StrOption('val1', "", multi=True, default=['val1', 'val2'])
911     val2 = StrOption('val2', "", multi=True, callback=return_list, callback_params={'value': ((val1, False),)})
912     oval2 = OptionDescription('val2', '', [val2])
913     maconfig = OptionDescription('rootconfig', '', [val1, oval2])
914     cfg = Config(maconfig)
915     cfg.read_write()
916     assert cfg.val2.val2 == ['val', 'val']
917
918
919 def test_masterslaves_callback_description():
920     st1 = StrOption('st1', "", multi=True)
921     st2 = StrOption('st2', "", multi=True, callback=return_value, callback_params={'': ((st1, False),)})
922     stm = OptionDescription('st1', '', [st1, st2])
923     stm.impl_set_group_type(groups.master)
924     st = OptionDescription('st', '', [stm])
925     od = OptionDescription('od', '', [st])
926     od2 = OptionDescription('od', '', [od])
927     cfg = Config(od2)
928     owner = cfg.cfgimpl_get_settings().getowner()
929     st1 = cfg.unwrap_from_path('od.st.st1.st1')
930     st2 = cfg.unwrap_from_path('od.st.st1.st2')
931     assert cfg.od.st.st1.st1 == []
932     assert cfg.od.st.st1.st2 == []
933     assert cfg.getowner(st1) == owners.default
934     assert cfg.getowner(st2) == owners.default
935     ##
936     cfg.od.st.st1.st1.append('yes')
937     assert cfg.od.st.st1.st1 == ['yes']
938     assert cfg.od.st.st1.st2 == ['yes']
939     assert cfg.getowner(st1) == owner
940
941
942 def test_re_set_callback():
943     st1 = StrOption('st1', "", multi=True)
944     st2 = StrOption('st2', "", multi=True)
945     st2.impl_set_callback(return_value, {'': ((st1, False),)})
946     raises(ConfigError, "st2.impl_set_callback(return_value, {'': ((st1, False),)})")