|
1 # |
|
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # |
|
16 |
|
17 import operator as ops |
|
18 import unittest |
|
19 import sys, os |
|
20 import __init__ |
|
21 import tokenize |
|
22 import StringIO |
|
23 |
|
24 from cone.public import api,exceptions, utils |
|
25 from cone.public.rules import ASTInterpreter, RelationContainerImpl |
|
26 from cone.public.rules import ParseException, DefaultContext, BaseRelation |
|
27 from cone.public import rules |
|
28 |
|
29 #### TEST RELATIONS #### |
|
30 |
|
31 AA_BA = 'a.a == "foo" requires b.b != 0' |
|
32 AB_BB = 'a.b configures b.b = a.b+":"+ "test"' |
|
33 BA_CA = 'b.a requires c.a and c.b and a.b' |
|
34 |
|
35 CB_DA = 'c.b requires d.a' |
|
36 DA_DB = 'd.a requires d.b' |
|
37 |
|
38 AC_AB_BA = 'a.c and a.a requires b.a' |
|
39 |
|
40 EA_FSTAR = 'e.a requires f.*' |
|
41 |
|
42 TEST_RELATIONS = { |
|
43 'a.a' : [AA_BA, 'a.a == "test" requires b.a'], |
|
44 'a.b' : [AB_BB], |
|
45 'a.c' : [AC_AB_BA], |
|
46 'b.a' : [BA_CA], |
|
47 'c.b' : [CB_DA], |
|
48 'd.a' : [DA_DB], |
|
49 'e.a' : [EA_FSTAR] |
|
50 } |
|
51 |
|
52 def get_test_configuration(): |
|
53 config = api.Configuration() |
|
54 config.add_feature(api.Feature('a')) |
|
55 config.add_feature(api.Feature('a'),'a') |
|
56 config.add_feature(api.Feature('b'),'a') |
|
57 config.add_feature(api.Feature('c'),'a') |
|
58 config.add_feature(api.Feature('b')) |
|
59 config.add_feature(api.Feature('a'),'b') |
|
60 config.add_feature(api.Feature('b'),'b') |
|
61 config.add_feature(api.Feature('c')) |
|
62 config.add_feature(api.Feature('a'),'c') |
|
63 config.add_feature(api.Feature('b'),'c') |
|
64 config.add_feature(api.Feature('d')) |
|
65 config.add_feature(api.Feature('a'),'d') |
|
66 config.add_feature(api.Feature('b'),'d') |
|
67 config.add_feature(api.Feature('e')) |
|
68 config.add_feature(api.Feature('a'),'e') |
|
69 dview = config.get_default_view() |
|
70 dview.get_feature('a.a').set_value('test') |
|
71 dview.get_feature('a.b').set_value('hey') |
|
72 dview.get_feature('a.c').set_value(False) |
|
73 dview.get_feature('b.a').set_value(True) |
|
74 dview.get_feature('b.b').set_value(True) |
|
75 dview.get_feature('c.a').set_value(True) |
|
76 dview.get_feature('c.b').set_value(True) |
|
77 dview.get_feature('d.a').set_value(False) |
|
78 dview.get_feature('d.b').set_value(False) |
|
79 return config |
|
80 |
|
81 class TestFactory(): |
|
82 def get_relations_for(self, configuration, ref): |
|
83 rels = TEST_RELATIONS.get(ref) |
|
84 if rels: |
|
85 relation_container = RelationContainerImpl() |
|
86 for rel in rels: |
|
87 (left_expression,relation_name,right_expression) = parse_rule(rel) |
|
88 relation = rules.RELATIONS.get(relation_name)(configuration, left_expression, right_expression) |
|
89 relation_container.add_relation(relation) |
|
90 propagated_relations = self.get_relations_for(configuration, right_expression) |
|
91 if propagated_relations: |
|
92 for relation in propagated_relations: |
|
93 relation_container.add_relation(relation) |
|
94 return relation_container |
|
95 return None |
|
96 |
|
97 def parse_rule(rulestring): |
|
98 """ |
|
99 Divide the given rule string into (left side, relation, right side) components. |
|
100 @return: Triple (left side, relation, right side) |
|
101 """ |
|
102 left_expression = '' |
|
103 relation_name = None |
|
104 right_expression = '' |
|
105 for token in rules.get_tokens(rulestring): |
|
106 if relation_name == None: |
|
107 if token in rules.RELATIONS.keys(): |
|
108 relation_name = token |
|
109 else: |
|
110 left_expression += ' ' + token |
|
111 else: |
|
112 right_expression += ' ' + token |
|
113 |
|
114 if relation_name == None: |
|
115 raise exceptions.ParseError('invalid rule definition %s' % rulestring) |
|
116 |
|
117 return (left_expression,relation_name,right_expression) |
|
118 |
|
119 class ConfigurationContext(DefaultContext): |
|
120 def handle_terminal(self, expression): |
|
121 try: |
|
122 value = self.data.get_feature(expression).get_value() |
|
123 if value != None: |
|
124 #print "handle_terminal %s = %s" % (expression,value) |
|
125 return value |
|
126 else: |
|
127 raise exceptions.NotBound('Feature %s has no value' % expression) |
|
128 except exceptions.NotFound,e: |
|
129 """ return the expression itself if it is not a fearef """ |
|
130 #print "handle_terminal constant %s" % (expression) |
|
131 try: |
|
132 return eval(expression) |
|
133 except (NameError,SyntaxError), e: |
|
134 return expression |
|
135 |
|
136 def eval(self, ast, expression, value): |
|
137 #print "expression %s = %s" % (expression,value) |
|
138 pass |
|
139 |
|
140 class ConfigurationBaseRelation(BaseRelation): |
|
141 def __init__(self, data, left, right): |
|
142 self.context = ConfigurationContext(data) |
|
143 super(ConfigurationBaseRelation, self).__init__(data, left, right) |
|
144 |
|
145 class RequireRelation(ConfigurationBaseRelation): |
|
146 KEY = 'requires' |
|
147 def __init__(self, data, left, right): |
|
148 super(RequireRelation, self).__init__(data, left, right) |
|
149 self.context = ConfigurationContext(data) |
|
150 |
|
151 class ConfigureRelation(ConfigurationBaseRelation): |
|
152 KEY = 'configures' |
|
153 def __init__(self, data, left, right): |
|
154 super(ConfigureRelation, self).__init__(data, left, right) |
|
155 self.context = ConfigurationContext(data) |
|
156 |
|
157 def handle_configure(self, left, right): |
|
158 if left and right: |
|
159 return True |
|
160 elif not left: |
|
161 return True |
|
162 return False |
|
163 |
|
164 def handle_set(self, left, right): |
|
165 left.set_value(right) |
|
166 |
|
167 class ConfigureExpression(rules.TwoOperatorExpression): |
|
168 PRECEDENCE = rules.PRECEDENCES['RELATION_OPERATORS'] |
|
169 KEY = 'configures' |
|
170 OP = handle_configure |
|
171 |
|
172 def eval(self, context): |
|
173 super(ConfigureExpression, self).eval(context) |
|
174 if not self.value: |
|
175 left_keys = [] |
|
176 for ref in self.ast.extract_refs(str(self.left)): |
|
177 for key in context.get_keys(ref): |
|
178 left_keys.append(key) |
|
179 |
|
180 for key in left_keys: |
|
181 self.ast.add_error(key, { 'error_string' : 'CONFIGURES right side value is "False"', |
|
182 'left_key' : key, |
|
183 'rule' : self.ast.expression |
|
184 }) |
|
185 return self.value |
|
186 |
|
187 def handle_plus(self, a,b): |
|
188 #print "%s adding a: %s to b: %s" % (self, a,b) |
|
189 return a + b |
|
190 |
|
191 class ConcatExpression(rules.TwoOperatorExpression): |
|
192 PRECEDENCE = rules.PRECEDENCES['ADDSUB_OPERATORS'] |
|
193 KEY= '+' |
|
194 OP = handle_plus |
|
195 |
|
196 |
|
197 class SetExpression(rules.TwoOperatorExpression): |
|
198 PRECEDENCE = rules.PRECEDENCES['SET_OPERATORS'] |
|
199 KEY= '=' |
|
200 OP = handle_set |
|
201 |
|
202 def eval(self, context): |
|
203 try: |
|
204 variable = context.data.get_feature(self.left.expression) |
|
205 variable.set_value(self.right.eval(context)) |
|
206 return True |
|
207 except exceptions.NotFound: |
|
208 return False |
|
209 |
|
210 class TestRelations(unittest.TestCase): |
|
211 |
|
212 def setUp(self): |
|
213 self.configuration = get_test_configuration() |
|
214 |
|
215 self.RELATIONS_BACKUP = rules.RELATIONS |
|
216 self.OPERATORS_BACKUP = rules.OPERATORS |
|
217 rules.RELATIONS = rules.RELATIONS.copy() |
|
218 rules.OPERATORS = rules.OPERATORS.copy() |
|
219 self.assertTrue(self.RELATIONS_BACKUP is not rules.RELATIONS) |
|
220 self.assertTrue(self.OPERATORS_BACKUP is not rules.OPERATORS) |
|
221 |
|
222 rules.RELATIONS[RequireRelation.KEY] = RequireRelation |
|
223 rules.RELATIONS[ConfigureRelation.KEY] = ConfigureRelation |
|
224 rules.OPERATORS[ConfigureExpression.KEY] = ConfigureExpression |
|
225 rules.OPERATORS[ConcatExpression.KEY] = ConcatExpression |
|
226 rules.OPERATORS[SetExpression.KEY] = SetExpression |
|
227 |
|
228 def tearDown(self): |
|
229 rules.RELATIONS = self.RELATIONS_BACKUP |
|
230 rules.OPERATORS = self.OPERATORS_BACKUP |
|
231 |
|
232 def test_has_ref(self): |
|
233 """ |
|
234 Tests the relation and relation container |
|
235 """ |
|
236 factory = TestFactory() |
|
237 rels = factory.get_relations_for(self.configuration, 'a.a') |
|
238 ret= rels.execute() |
|
239 self.assertTrue(ret) |
|
240 |
|
241 def test_has_ref(self): |
|
242 """ |
|
243 Tests the relation and relation container |
|
244 """ |
|
245 factory = TestFactory() |
|
246 rels = factory.get_relations_for(self.configuration, 'a.a') |
|
247 ret= rels.execute() |
|
248 self.assertTrue(ret) |
|
249 |
|
250 def test_not_has_ref(self): |
|
251 factory = TestFactory() |
|
252 # depends on c.a which has no value in conf |
|
253 rels = factory.get_relations_for(self.configuration, 'b.a') |
|
254 ret = rels.execute() |
|
255 self.assertTrue(ret) |
|
256 |
|
257 def test_not_has_ref_in_container(self): |
|
258 factory = TestFactory() |
|
259 rels = factory.get_relations_for(self.configuration, 'c.b') |
|
260 ret = rels.execute() |
|
261 self.assertFalse(ret) |
|
262 |
|
263 def test_two_on_the_left(self): |
|
264 factory = TestFactory() |
|
265 rels = factory.get_relations_for(self.configuration, 'a.c') |
|
266 ret = rels.execute() |
|
267 self.assertTrue(ret) |
|
268 |
|
269 def test_configure_right_side(self): |
|
270 factory = TestFactory() |
|
271 rels = factory.get_relations_for(self.configuration, 'a.b') |
|
272 ret = rels.execute() |
|
273 self.assertTrue(ret) |
|
274 self.assertEquals(self.configuration.get_default_view().get_feature('b.b').get_value(),'hey:test') |
|
275 |
|
276 if __name__ == '__main__': |
|
277 unittest.main() |