Fix ItemMatcher to avoid false positives

As stated in a TODO ItemMatcher returns True on [1, 1, 2] ?= [1, 2, 2].
This patch changes the internal implementation from set() to
collection.Counter to remove this false positive.

Change-Id: I1e8fccf3967dfcb464674d9e2d8f7d93eb015a83
This commit is contained in:
Balazs Gibizer 2019-10-21 10:17:11 +02:00
parent acb8b7c4a4
commit f893aa5ad1
1 changed files with 8 additions and 9 deletions

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import errno
import platform
import socket
@ -322,22 +323,20 @@ class ItemsMatcher(CustomMockCallMatcher):
But the following will fail::
my_mock(..., listy_kwarg=['foo', 'bar'], ...)
.. todo:: Because we internally use set()s, the following will **pass**,
but it shouldn't::
# Duplicated item
my_mock(..., listy_kwarg=['foo', 'foo', 'bar', 'baz'], ...)
"""
def __init__(self, iterable):
self.items = set(iterable)
# NOTE(gibi): we need the extra iter() call as Counter handles dicts
# directly to initialize item count. However if a dict passed to
# ItemMatcher we want to use the keys of such dict as an iterable to
# initialize the Counter instead.
self.bag = collections.Counter(iter(iterable))
super(ItemsMatcher, self).__init__(
lambda other: self.items == set(other))
lambda other: self.bag == collections.Counter(iter(other)))
def __repr__(self):
"""This exists so a failed assertion prints something useful."""
return 'ItemsMatcher(%r)' % self.items
return 'ItemsMatcher(%r)' % list(self.bag.elements())
def assert_instance_delete_notification_by_uuid(