[ 
https://issues.apache.org/jira/browse/BEAM-2970?focusedWorklogId=99704&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-99704
 ]

ASF GitHub Bot logged work on BEAM-2970:
----------------------------------------

                Author: ASF GitHub Bot
            Created on: 08/May/18 20:23
            Start Date: 08/May/18 20:23
    Worklog Time Spent: 10m 
      Work Description: chamikaramj closed pull request #3878: [BEAM-2970] Add 
contains_in_any_order matcher
URL: https://github.com/apache/beam/pull/3878
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/sdks/python/apache_beam/testing/util.py 
b/sdks/python/apache_beam/testing/util.py
index 9bb18ccccb7..c2712e1dbaf 100644
--- a/sdks/python/apache_beam/testing/util.py
+++ b/sdks/python/apache_beam/testing/util.py
@@ -19,6 +19,7 @@
 
 from __future__ import absolute_import
 
+import copy
 import glob
 import tempfile
 
@@ -33,6 +34,7 @@
 
 __all__ = [
     'assert_that',
+    'contains_in_any_order',
     'equal_to',
     'is_empty',
     # open_shards is internal and has no backwards compatibility guarantees.
@@ -50,7 +52,6 @@ class BeamAssertException(Exception):
 # compare are PCollections for which there is no guaranteed order.
 # However the sorting does not go beyond top level therefore [1,2] and [2,1]
 # are considered equal and [[1,2]] and [[2,1]] are not.
-# TODO(silviuc): Add contains_in_any_order-style matchers.
 def equal_to(expected):
   expected = list(expected)
 
@@ -63,6 +64,46 @@ def _equal(actual):
   return _equal
 
 
+def contains_in_any_order(predicates):
+  """Create a matcher to check that an iterable maps to a list of predicates.
+
+  Args:
+    predicates: a list of predicate functions that take a value from the
+      iterable as argument and return True to indicate a match and False to
+      indicate a non-match.
+
+  Returns:
+    A matcher that operates on iterables and raises an error if any of the
+      following are true:
+      - the length of the list of predicates is not equal to the length of the
+      iterable.
+      - there isn't a way to create a one-to-one mapping from items i in the
+      iterable to predicates p such that p(i) == True for all i.
+  """
+  def _contains_in_any_order(all_items, all_predicates):
+    stack = [(all_items, all_predicates)]
+
+    # Perform a depth-first search to find a mapping from items in the
+    # iterable to predicates they satisfy.
+    while len(stack) > 0:
+      items, predicates = stack[0]
+      stack = stack[1:]
+      if items == []:
+        return predicates == []
+      for i, p in enumerate(predicates):
+        remaining_predicates = copy.copy(predicates)
+        del remaining_predicates[i]
+        if p(items[0]):
+          stack = [(items[1:], remaining_predicates)] + stack
+    return False
+
+  def _matcher(actual):
+    if not _contains_in_any_order(actual, predicates):
+      raise BeamAssertException('Failed assert: %r contains_in_any_order %r' %
+                                (actual, predicates))
+  return _matcher
+
+
 def is_empty():
   def _empty(actual):
     actual = list(actual)
diff --git a/sdks/python/apache_beam/testing/util_test.py 
b/sdks/python/apache_beam/testing/util_test.py
index 9d3869381b6..fd444882cb9 100644
--- a/sdks/python/apache_beam/testing/util_test.py
+++ b/sdks/python/apache_beam/testing/util_test.py
@@ -22,27 +22,54 @@
 from apache_beam import Create
 from apache_beam.testing.test_pipeline import TestPipeline
 from apache_beam.testing.util import assert_that
+from apache_beam.testing.util import contains_in_any_order
 from apache_beam.testing.util import equal_to
 from apache_beam.testing.util import is_empty
 
 
 class UtilTest(unittest.TestCase):
 
-  def test_assert_that_passes(self):
+  def test_assert_that_equal_to_passes(self):
     with TestPipeline() as p:
       assert_that(p | Create([1, 2, 3]), equal_to([1, 2, 3]))
 
-  def test_assert_that_fails(self):
+  def test_assert_that_equal_to_fails(self):
     with self.assertRaises(Exception):
       with TestPipeline() as p:
         assert_that(p | Create([1, 10, 100]), equal_to([1, 2, 3]))
 
-  def test_assert_that_fails_on_empty_input(self):
+  def test_assert_that_equal_to_fails_on_empty_input(self):
     with self.assertRaises(Exception):
       with TestPipeline() as p:
         assert_that(p | Create([]), equal_to([1, 2, 3]))
 
-  def test_assert_that_fails_on_empty_expected(self):
+  def test_assert_that_contains_in_any_order_passes(self):
+    with TestPipeline() as p:
+      assert_that(p | Create([5, 50]), contains_in_any_order(
+          [lambda x: x > 0, lambda x: x < 10]))
+
+  def test_assert_that_contains_in_any_order_fails(self):
+    with self.assertRaises(Exception):
+      with TestPipeline() as p:
+        assert_that(p | Create([5, 50]), contains_in_any_order(
+            [lambda x: x > 0, lambda x: x < 0]))
+
+  def test_assert_that_contains_in_any_order_fails_on_empty_predicates(self):
+    with self.assertRaises(Exception):
+      with TestPipeline() as p:
+        assert_that(p | Create([5, 50]), contains_in_any_order([]))
+
+  def 
test_assert_that_contains_in_any_order_fails_on_too_many_predicates(self):
+    with self.assertRaises(Exception):
+      with TestPipeline() as p:
+        assert_that(p | Create([5, 50]), contains_in_any_order(
+            [lambda x: x > 0, lambda x: x < 10, lambda x: x == 5]))
+
+  def test_assert_that_is_empty_passes(self):
+    with TestPipeline() as p:
+      assert_that(p | Create([]), is_empty())
+
+  def test_assert_that_is_empty_fails(self):
     with self.assertRaises(Exception):
       with TestPipeline() as p:
         assert_that(p | Create([1, 2, 3]), is_empty())


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


Issue Time Tracking
-------------------

    Worklog Id:     (was: 99704)
    Time Spent: 20m  (was: 10m)

> Add comparator function to equal_to
> -----------------------------------
>
>                 Key: BEAM-2970
>                 URL: https://issues.apache.org/jira/browse/BEAM-2970
>             Project: Beam
>          Issue Type: Improvement
>          Components: sdk-py-core
>            Reporter: Sarah Walters
>            Assignee: Ahmet Altay
>            Priority: Minor
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> The equal_to function provided by testing/util.py 
> (https://github.com/apache/beam/blob/master/sdks/python/apache_beam/testing/util.py#L54)
>  assumes that the actual and expected lists can be sorted using Python's 
> sorted method (which relies on the < operator) and compared using the == 
> operator.
> If this isn't the case, equal_to sometimes reports False incorrectly, when 
> the expected and actual lists are in different orders.
> Add a comparator function to equal_to in order to allow callers to define a 
> total order.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to