Commit 2ae039a0 authored by Anthony Polito's avatar Anthony Polito Committed by Commit Bot

Add support for multi argument ands and ors, and the same precedence with

left to right grouping

Bug: 905740
Change-Id: I6a0b971556ab66bec841004fbbe8760b9136f216
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/1793775Reviewed-by: 's avatarEdward Lesmes <ehmaldonado@chromium.org>
Commit-Queue: Anthony Polito <apolito@google.com>
parent cc6f585f
...@@ -568,33 +568,23 @@ def EvaluateCondition(condition, variables, referenced_variables=None): ...@@ -568,33 +568,23 @@ def EvaluateCondition(condition, variables, referenced_variables=None):
node, ast.NameConstant): # Since Python 3.4 node, ast.NameConstant): # Since Python 3.4
return node.value return node.value
elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or): elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or):
if len(node.values) != 2: bool_values = []
raise ValueError( for value in node.values:
'invalid "or": exactly 2 operands required (inside %r)' % ( bool_values.append(_convert(value))
condition)) if not isinstance(bool_values[-1], bool):
left = _convert(node.values[0]) raise ValueError(
right = _convert(node.values[1]) 'invalid "or" operand %r (inside %r)' % (
if not isinstance(left, bool): bool_values[-1], condition))
raise ValueError( return any(bool_values)
'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
elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.And): elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.And):
if len(node.values) != 2: bool_values = []
raise ValueError( for value in node.values:
'invalid "and": exactly 2 operands required (inside %r)' % ( bool_values.append(_convert(value))
condition)) if not isinstance(bool_values[-1], bool):
left = _convert(node.values[0]) raise ValueError(
right = _convert(node.values[1]) 'invalid "and" operand %r (inside %r)' % (
if not isinstance(left, bool): bool_values[-1], condition))
raise ValueError( return all(bool_values)
'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
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not): elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
value = _convert(node.operand) value = _convert(node.operand)
if not isinstance(value, bool): if not isinstance(value, bool):
......
...@@ -250,6 +250,26 @@ class EvaluateConditionTest(unittest.TestCase): ...@@ -250,6 +250,26 @@ class EvaluateConditionTest(unittest.TestCase):
self.assertFalse(gclient_eval.EvaluateCondition( self.assertFalse(gclient_eval.EvaluateCondition(
'foo != "baz"', {'foo': '"baz"'})) '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): def test_string_bool(self):
self.assertFalse(gclient_eval.EvaluateCondition( self.assertFalse(gclient_eval.EvaluateCondition(
'false_str_var and true_var', 'false_str_var and true_var',
...@@ -265,6 +285,26 @@ class EvaluateConditionTest(unittest.TestCase): ...@@ -265,6 +285,26 @@ class EvaluateConditionTest(unittest.TestCase):
'(inside \'false_var_str and true_var\')', '(inside \'false_var_str and true_var\')',
str(cm.exception)) 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): def test_tuple_presence(self):
self.assertTrue(gclient_eval.EvaluateCondition( self.assertTrue(gclient_eval.EvaluateCondition(
'foo in ("bar", "baz")', {'foo': 'bar'})) 'foo in ("bar", "baz")', {'foo': 'bar'}))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment