mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
175 lines
4.4 KiB
Python
175 lines
4.4 KiB
Python
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
# Licensed under the MIT License. See LICENSE in the project root
|
|
# for license information.
|
|
|
|
from __future__ import print_function, with_statement, absolute_import
|
|
|
|
import numbers
|
|
import re
|
|
|
|
from ptvsd.compat import unicode
|
|
from tests.helpers.pathutils import compare_path
|
|
|
|
|
|
class BasePattern(object):
|
|
|
|
def __repr__(self):
|
|
raise NotImplementedError()
|
|
|
|
def __eq__(self, value):
|
|
raise NotImplementedError()
|
|
|
|
def such_that(self, condition):
|
|
return Maybe(self, condition)
|
|
|
|
|
|
class Any(BasePattern):
|
|
"""Represents a wildcard in a pattern as used by json_matches(),
|
|
and matches any single object in the same place in input data.
|
|
"""
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def __repr__(self):
|
|
return 'ANY'
|
|
|
|
def __eq__(self, other):
|
|
return True
|
|
|
|
@staticmethod
|
|
def dict_with(items):
|
|
"""A pattern that matches any dict that contains the specified key-value pairs.
|
|
|
|
d1 = {'a': 1, 'b': 2, 'c': 3}
|
|
d2 = {'a': 1, 'b': 2}
|
|
|
|
d1 == Pattern(d2) # False (need exact match)
|
|
d1 == ANY.dict_with(d2) # True (subset matches)
|
|
"""
|
|
|
|
class AnyDictWith(dict):
|
|
|
|
def __repr__(self):
|
|
return repr(items)[:-1] + ', ...}'
|
|
|
|
def __eq__(self, other):
|
|
if not isinstance(other, dict):
|
|
return NotImplemented
|
|
d = {key: ANY for key in other}
|
|
d.update(self)
|
|
return d == other
|
|
|
|
def __ne__(self, other):
|
|
return not (self == other)
|
|
|
|
items = dict(items)
|
|
return AnyDictWith(items)
|
|
|
|
|
|
class Maybe(BasePattern):
|
|
"""A pattern that matches if condition is True.
|
|
"""
|
|
|
|
name = None
|
|
|
|
def __init__(self, pattern, condition):
|
|
self.pattern = pattern
|
|
self.condition = condition
|
|
|
|
def __repr__(self):
|
|
return self.name or 'Maybe(%r)' % self.pattern
|
|
|
|
def __eq__(self, value):
|
|
return self.condition(value) and value == self.pattern
|
|
|
|
|
|
class Success(BasePattern):
|
|
"""A pattern that matches a response body depending on whether the request succeeded or failed.
|
|
"""
|
|
|
|
def __init__(self, success):
|
|
self.success = success
|
|
|
|
def __repr__(self):
|
|
return 'SUCCESS' if self.success else 'FAILURE'
|
|
|
|
def __eq__(self, response_body):
|
|
return self.success != isinstance(response_body, Exception)
|
|
|
|
|
|
class Is(BasePattern):
|
|
"""A pattern that matches a specific object only (i.e. uses operator 'is' rather than '==').
|
|
"""
|
|
|
|
def __init__(self, obj):
|
|
self.obj = obj
|
|
|
|
def __repr__(self):
|
|
return 'Is(%r)' % self.obj
|
|
|
|
def __eq__(self, value):
|
|
return self.obj is value
|
|
|
|
|
|
class Path(object):
|
|
"""A pattern that matches strings as path, using os.path.normcase before comparison,
|
|
and sys.getfilesystemencoding() to compare Unicode and non-Unicode strings.
|
|
"""
|
|
|
|
def __init__(self, s):
|
|
self.s = s
|
|
|
|
def __repr__(self):
|
|
return 'Path(%r)' % (self.s,)
|
|
|
|
def __eq__(self, other):
|
|
if not (isinstance(other, bytes) or isinstance(other, unicode)):
|
|
return NotImplemented
|
|
return compare_path(self.s, other, show=False)
|
|
|
|
def __ne__(self, other):
|
|
return not (self == other)
|
|
|
|
|
|
class Regex(object):
|
|
"""A pattern that matches strings against regex, as if with re.match().
|
|
"""
|
|
|
|
def __init__(self, regex):
|
|
self.regex = regex
|
|
|
|
def __repr__(self):
|
|
return '/%s/' % (self.regex,)
|
|
|
|
def __eq__(self, other):
|
|
if not (isinstance(other, bytes) or isinstance(other, unicode)):
|
|
return NotImplemented
|
|
return re.match(self.regex, other)
|
|
|
|
def __ne__(self, other):
|
|
return not (self == other)
|
|
|
|
|
|
SUCCESS = Success(True)
|
|
FAILURE = Success(False)
|
|
|
|
ANY = Any()
|
|
|
|
ANY.bool = ANY.such_that(lambda x: x is True or x is False)
|
|
ANY.bool.name = 'ANY.bool'
|
|
|
|
ANY.str = ANY.such_that(lambda x: isinstance(x, unicode))
|
|
ANY.str.name = 'ANY.str'
|
|
|
|
ANY.num = ANY.such_that(lambda x: isinstance(x, numbers.Real))
|
|
ANY.num.name = 'ANY.num'
|
|
|
|
ANY.int = ANY.such_that(lambda x: isinstance(x, numbers.Integral))
|
|
ANY.int.name = 'ANY.int'
|
|
|
|
# Note: in practice it could be any int32, but as in those cases we expect the number to be
|
|
# incremented sequentially, this should be reasonable for tests.
|
|
ANY.dap_id = ANY.such_that(lambda x: isinstance(x, numbers.Integral) and 0 <= x < 10000)
|
|
ANY.dap_id.name = 'ANY.dap_id'
|
|
|