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):
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):
......
......@@ -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'}))
......
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