from mongows.mws.db import get_db
from mongows.mws.util import UseResId
from abc import ABCMeta, abstractmethod
from collections import Counter


class ValidationTest:
    __metaclass__ = ABCMeta

    def __init__(self, res_id):
        self.res_id = res_id
        self.db = get_db()

    def __hashDict(self, d):
        for key in d:
            if isinstance(d[key], dict):
                d[key] = __hashDict(d[key])
        return tuple(d.items())

    # Collection must exactly equal the data set
    def collection_equals(self, collection, data, check_id=False):
        data = [self.__hashDict(x) for x in data]
        with UseResId(self.res_id):
            projection = None if check_id else {'_id': 0}
            result = list(self.db[collection].find({}, projection))
            result = [self.__hashDict(x) for x in result]
            return Counter(result) == Counter(data)

    # Data must be a subset of collection
    def collection_contains(self, collection, data, check_id=False):
        with UseResId(self.res_id):
            projection = None if check_id else {'_id': 0}
            result = list(self.db[collection].find({'$or': data}, projection))
            return all(x in result for x in data)

    # Collection must contain one or more of the elements in data
    def collection_contains_any(self, collection, data, check_id=False):
        with UseResId(self.res_id):
            projection = None if check_id else {'_id': 0}
            result = list(self.db[collection].find({'$or': data}, projection))
            return any(x in result for x in data)

    # Collection does not contain any of the elements in data
    def collection_contains_none(self, collection, data, check_id=False):
        return not self.collection_contains_any(collection, data, check_id)

    # Require all inheriting classes to implement a run method
    @abstractmethod
    def run(self):
        pass

@@ -579,17 +579,17 @@
  data = 
-%5B
+(
 self.__h
@@ -612,17 +612,17 @@
  in data
-%5D
+)
 %0A       
@@ -721,37 +721,32 @@
        result = 
-list(
 self.db%5Bcollecti
@@ -761,33 +761,32 @@
 (%7B%7D, projection)
-)
 %0A            res
@@ -791,17 +791,17 @@
 esult = 
-%5B
+(
 self.__h
@@ -826,17 +826,17 @@
 n result
-%5D
+)
 %0A       
@@ -1181,36 +1181,177 @@
     
-return all(x in result
+data = Counter(self.__hashDict(x) for x in data)%0A            result = Counter(self.__hashDict(x) for x in result)%0A            return all(data%5Bkey%5D %3C= result%5Bkey%5D
  for 
-x
+key
  in 
@@ -1582,32 +1582,32 @@
 else %7B'_id': 0%7D%0A
-
             resu
@@ -1661,32 +1661,144 @@
 %7D, projection))%0A
+            data = %7Bself.__hashDict(x) for x in data%7D%0A            result = %7Bself.__hashDict(x) for x in result%7D%0A
             retu

fix validation util computation