From f893aa5ad14e1747eedafeb75be3f48eade7fd98 Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Mon, 21 Oct 2019 10:17:11 +0200 Subject: [PATCH] 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 --- nova/tests/unit/utils.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/nova/tests/unit/utils.py b/nova/tests/unit/utils.py index 3d765dc2d3..8ac1a8163b 100644 --- a/nova/tests/unit/utils.py +++ b/nova/tests/unit/utils.py @@ -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(