diff --git a/gclient_eval.py b/gclient_eval.py index c32677ccc..66656ae86 100644 --- a/gclient_eval.py +++ b/gclient_eval.py @@ -568,33 +568,23 @@ def EvaluateCondition(condition, variables, referenced_variables=None): node, ast.NameConstant): # Since Python 3.4 return node.value elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or): - if len(node.values) != 2: - raise ValueError( - 'invalid "or": exactly 2 operands required (inside %r)' % ( - condition)) - left = _convert(node.values[0]) - right = _convert(node.values[1]) - if not isinstance(left, bool): - raise ValueError( - 'invalid "or" operand %r (inside %r)' % (left, condition)) - if not isinstance(right, bool): - raise ValueError( - 'invalid "or" operand %r (inside %r)' % (right, condition)) - return left or right + bool_values = [] + for value in node.values: + bool_values.append(_convert(value)) + if not isinstance(bool_values[-1], bool): + raise ValueError( + 'invalid "or" operand %r (inside %r)' % ( + bool_values[-1], condition)) + return any(bool_values) elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.And): - if len(node.values) != 2: - raise ValueError( - 'invalid "and": exactly 2 operands required (inside %r)' % ( - condition)) - left = _convert(node.values[0]) - right = _convert(node.values[1]) - if not isinstance(left, bool): - raise ValueError( - 'invalid "and" operand %r (inside %r)' % (left, condition)) - if not isinstance(right, bool): - raise ValueError( - 'invalid "and" operand %r (inside %r)' % (right, condition)) - return left and right + bool_values = [] + for value in node.values: + bool_values.append(_convert(value)) + if not isinstance(bool_values[-1], bool): + raise ValueError( + 'invalid "and" operand %r (inside %r)' % ( + bool_values[-1], condition)) + return all(bool_values) elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not): value = _convert(node.operand) if not isinstance(value, bool): diff --git a/tests/gclient_eval_unittest.py b/tests/gclient_eval_unittest.py index 03a460ee1..dfb2813d6 100755 --- a/tests/gclient_eval_unittest.py +++ b/tests/gclient_eval_unittest.py @@ -250,6 +250,26 @@ class EvaluateConditionTest(unittest.TestCase): self.assertFalse(gclient_eval.EvaluateCondition( 'foo != "baz"', {'foo': '"baz"'})) + def test_triple_or(self): + self.assertTrue(gclient_eval.EvaluateCondition( + 'a or b or c', {'a': 'False', 'b': 'False', 'c': 'True'})) + self.assertFalse(gclient_eval.EvaluateCondition( + 'a or b or c', {'a': 'False', 'b': 'False', 'c': 'False'})) + + def test_triple_and(self): + self.assertTrue(gclient_eval.EvaluateCondition( + 'a and b and c', {'a': 'True', 'b': 'True', 'c': 'True'})) + self.assertFalse(gclient_eval.EvaluateCondition( + 'a and b and c', {'a': 'True', 'b': 'True', 'c': 'False'})) + + def test_triple_and_and_or(self): + self.assertTrue(gclient_eval.EvaluateCondition( + 'a and b and c or d or e', + {'a': 'False', 'b': 'False', 'c': 'False', 'd': 'False', 'e': 'True'})) + self.assertFalse(gclient_eval.EvaluateCondition( + 'a and b and c or d or e', + {'a': 'True', 'b': 'True', 'c': 'False', 'd': 'False', 'e': 'False'})) + def test_string_bool(self): self.assertFalse(gclient_eval.EvaluateCondition( 'false_str_var and true_var', @@ -265,6 +285,26 @@ class EvaluateConditionTest(unittest.TestCase): '(inside \'false_var_str and true_var\')', str(cm.exception)) + def test_non_bool_in_or(self): + with self.assertRaises(ValueError) as cm: + gclient_eval.EvaluateCondition( + 'string_var or true_var', + {'string_var': 'Kittens', 'true_var': True}) + self.assertIn( + 'invalid "or" operand \'Kittens\' ' + '(inside \'string_var or true_var\')', + str(cm.exception)) + + def test_non_bool_in_and(self): + with self.assertRaises(ValueError) as cm: + gclient_eval.EvaluateCondition( + 'string_var and true_var', + {'string_var': 'Kittens', 'true_var': True}) + self.assertIn( + 'invalid "and" operand \'Kittens\' ' + '(inside \'string_var and true_var\')', + str(cm.exception)) + def test_tuple_presence(self): self.assertTrue(gclient_eval.EvaluateCondition( 'foo in ("bar", "baz")', {'foo': 'bar'}))