def test_missing_op(self): encoded = '%28a%253D1%29%28b%253D2%29%26%28c%253D3%29' readable = '(a%3D1)(b%3D2)&(c%3D3)' self.assertEqual(encode(readable), encoded) with self.assertRaises(ValidationError) as exc: decode_complex_ops(encoded) self.assertEqual(exc.exception.detail, ["Invalid querystring operator. Matched: ''."])
def test_duplicate_negation(self): encoded = '%28a%253D1%29%20%26%20~~%28b%253D2%29' readable = '(a%3D1) & ~~(b%3D2)' self.assertEqual(encode(readable), encoded) with self.assertRaises(ValidationError) as exc: decode_complex_ops(encoded) self.assertEqual(exc.exception.detail, ["Invalid querystring operator. Matched: ' & ~'."])
def test_missing_closing_paren(self): encoded = '%28a%253D1' readable = '(a%3D1' self.assertEqual(encode(readable), encoded) with self.assertRaises(ValidationError) as exc: decode_complex_ops(encoded) self.assertEqual(exc.exception.detail, [ "Unable to parse querystring. Decoded: '(a%3D1'.", ])
def test_tilde_decoding(self): # Ensure decoding handles both RFC 2396 & 3986 encoded_rfc3986 = '~%28a%253D1%29' encoded_rfc2396 = '%7E%28a%253D1%29' readable = '~(a%3D1)' result = [ ('a=1', True, None), ] self.assertEqual(encode(readable), encoded_rfc3986) self.assertEqual(decode_complex_ops(encoded_rfc3986), result) self.assertEqual(decode_complex_ops(encoded_rfc2396), result)
def test_invalid_ops(self): encoded = '%28a%253D1%29asdf%28b%253D2%29qwerty%28c%253D3%29%26' readable = '(a%3D1)asdf(b%3D2)qwerty(c%3D3)&' self.assertEqual(encode(readable), encoded) with self.assertRaises(ValidationError) as exc: decode_complex_ops(encoded) self.assertEqual(exc.exception.detail, [ "Invalid querystring operator. Matched: 'asdf'.", "Invalid querystring operator. Matched: 'qwerty'.", "Ending querystring must not have trailing characters. Matched: '&'.", ])
def filter_membership(self, qs, name, value): # Decode complex membership query try: complex_ops = decode_complex_ops(value, filter_operators(), True) except ValidationError as exc: raise ValidationError({'membership': exc.detail}) # Collect the individual filtered membership querysets querystrings = [op.querystring for op in complex_ops] ms_queryset = vendors.PoolMembership.objects.all() ms_querysets = [] errors = [] for qstring in querystrings: query = qstring.split('=') try: ms_querysets.append(ms_queryset.filter(**{query[0]: query[1]})) except ValidationError as exc: errors[qstring] = exc.detail if errors: raise ValidationError(errors) # Retrieve a list of membership ids matching query ms_queryset = combine_complex_queryset(ms_querysets, complex_ops) ms_ids = list(ms_queryset.values_list('id', flat=True)) # Filter vendors by membership if len(querystrings) > 0: qs = qs.filter(pools__id__in=ms_ids) return qs
def test_single_op(self): encoded = '%28a%253D1%29' readable = '(a%3D1)' result = [ ('a=1', False, None), ] self.assertEqual(encode(readable), encoded) self.assertEqual(decode_complex_ops(encoded), result)
def test_only_negation(self): encoded = '~%28a%253D1%29' readable = '~(a%3D1)' result = [ ('a=1', True, None), ] self.assertEqual(encode(readable), encoded) self.assertEqual(decode_complex_ops(encoded), result)
def filter_membership(self, qs, name, value): try: complex_ops = decode_complex_ops(value, filter_operators(), True) except ValidationError as exc: raise ValidationError({'membership': exc.detail}) # Collect the individual filtered membership querysets querystrings = [op.querystring for op in complex_ops] ms_queryset = vendors.PoolMembership.objects.all() ms_querysets = [] errors = [] poolIds = [] queryParameters = {} self.logger.error(" one ") for qstring in querystrings: query = qstring.split('=') try: if 'pool__id__in' == query[0]: poolIds = query[1].split(",") query[1] = poolIds queryParameters[query[0]] = query[1] ms_querysets.append(ms_queryset.filter(**{query[0]: query[1]})) except ValidationError as exc: errors[qstring] = exc.detail if (len(poolIds) <= 1): try: ms_queryset = combine_complex_queryset(ms_querysets, complex_ops) ms_ids = list(ms_queryset.values_list('id', flat=True)) self.logger.error(" ms_ids if {} ".format(ms_ids)) self.logger.error(" query if {} ".format(ms_queryset.query)) except ValidationError as exc: errors[qstring] = exc.detail else: try: self.logger.error(" poolIds else {} ".format(poolIds)) ms_queryset = combine_complex_queryset(ms_querysets, complex_ops) ms_ids = self.getMebershipIds(ms_queryset) self.logger.error(" ms_ids else {} ".format(ms_ids)) if len(ms_ids) == 0: qs = qs.filter(pools__id=0) return qs except ValidationError as exc: errors[qstring] = exc.detail if errors: raise ValidationError(errors) if len(querystrings) > 0: qs = qs.filter(pools__id__in=ms_ids) return qs
def test_op_spacing(self): encoded = '%28a%253D1%29%20%26%20%28b%253D2%29' readable = '(a%3D1) & (b%3D2)' result = [ ('a=1', False, QuerySet.__and__), ('b=2', False, None), ] self.assertEqual(encode(readable), encoded) self.assertEqual(decode_complex_ops(encoded), result)
def test_docstring(self): encoded = '%28a%253D1%29%20%26%20%28b%253D2%29%20%7C%20~%28c%253D3%29' readable = '(a%3D1) & (b%3D2) | ~(c%3D3)' result = [ ('a=1', False, QuerySet.__and__), ('b=2', False, QuerySet.__or__), ('c=3', True, None), ] self.assertEqual(encode(readable), encoded) self.assertEqual(decode_complex_ops(encoded), result)