Skip to content

Commit

Permalink
add support for object comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
ITProKyle committed Oct 3, 2023
1 parent ae38c16 commit b8e4e29
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 45 deletions.
110 changes: 68 additions & 42 deletions tests/test_basic.py
Expand Up @@ -5,6 +5,7 @@
AWSObject,
AWSProperty,
Cidr,
GenericHelperFn,
If,
Join,
NoValue,
Expand All @@ -24,7 +25,74 @@
from troposphere.validators import positive_integer


def double(x):
return positive_integer(x) * 2


def call_correct(x):
return x


def call_incorrect(x):
raise ValueError


class FakeAWSProperty(AWSProperty):
props = {}


class FakeAWSObject(AWSObject):
type = "Fake::AWS::Object"

props = {
"callcorrect": (call_correct, False),
"callincorrect": (call_incorrect, False),
"singlelist": (list, False),
"multilist": ([bool, int, float], False),
"multituple": ((bool, int), False),
"helperfun": (positive_integer, False),
"listhelperfun": ([double], False),
}

def validate(self):
properties = self.properties
title = self.title
type = self.type
if "callcorrect" in properties and "singlelist" in properties:
raise ValueError(
(
"Cannot specify both 'callcorrect and 'singlelist' in "
"object %s (type %s)" % (title, type)
)
)


class TestBasic(unittest.TestCase):
def test___eq__(self):
"""Test __eq__."""
assert FakeAWSObject("foobar", callcorrect=True) == FakeAWSObject(
"foobar", callcorrect=True
)
assert FakeAWSObject("foobar", callcorrect=True) == {
"title": "foobar",
"Properties": {"callcorrect": True},
}
assert GenericHelperFn("foobar") == GenericHelperFn("foobar")
assert GenericHelperFn({"foo": "bar"}) == {"foo": "bar"}

def test___ne__(self):
"""Test __ne__."""
assert FakeAWSObject("foo", callcorrect=True) != FakeAWSObject(
"bar", callcorrect=True
)
assert FakeAWSObject("foobar", callcorrect=True) != FakeAWSObject(
"foobar", callcorrect=False
)
assert FakeAWSObject("foobar", callcorrect=True) != FakeAWSProperty("foobar")
assert GenericHelperFn("foobar") != GenericHelperFn("bar")
assert GenericHelperFn("foobar") != "foobar"
assert GenericHelperFn("foobar") != FakeAWSProperty("foobar")

def test_badproperty(self):
with self.assertRaises(AttributeError):
Instance(
Expand Down Expand Up @@ -89,48 +157,6 @@ def test_pickle_ok(self):
self.assertEqual(b2.BucketName, b.BucketName)


def double(x):
return positive_integer(x) * 2


def call_correct(x):
return x


def call_incorrect(x):
raise ValueError


class FakeAWSObject(AWSObject):
type = "Fake::AWS::Object"

props = {
"callcorrect": (call_correct, False),
"callincorrect": (call_incorrect, False),
"singlelist": (list, False),
"multilist": ([bool, int, float], False),
"multituple": ((bool, int), False),
"helperfun": (positive_integer, False),
"listhelperfun": ([double], False),
}

def validate(self):
properties = self.properties
title = self.title
type = self.type
if "callcorrect" in properties and "singlelist" in properties:
raise ValueError(
(
"Cannot specify both 'callcorrect and 'singlelist' in "
"object %s (type %s)" % (title, type)
)
)


class FakeAWSProperty(AWSProperty):
props = {}


class TestValidators(unittest.TestCase):
def test_callcorrect(self):
FakeAWSObject("fake", callcorrect=True)
Expand Down
34 changes: 31 additions & 3 deletions troposphere/__init__.py
Expand Up @@ -351,6 +351,10 @@ def to_dict(self) -> Dict[str, Any]:
else:
return {}

def to_json(self, *, indent: int = 4, sort_keys: bool = True) -> str:
"""Object as JSON."""
return json.dumps(self.to_dict(), indent=indent, sort_keys=sort_keys)

@classmethod
def _from_dict(
cls: Type[__BaseAWSObjectTypeVar], title: Optional[str] = None, **kwargs: Any
Expand Down Expand Up @@ -411,6 +415,16 @@ def _validate_props(self) -> None:
msg += " (title: %s)" % title
raise ValueError(msg)

def __eq__(self, other: object) -> bool:
if isinstance(other, self.__class__):
return self.title == other.title and self.to_json() == other.to_json()
if isinstance(other, dict):
return {"title": self.title, **self.to_dict()} == other
return False

def __ne__(self, other: object) -> bool:
return not self == other


class AWSObject(BaseAWSObject):
dictname = "Properties"
Expand Down Expand Up @@ -491,16 +505,30 @@ def getdata(self, data: object) -> Any:
def to_dict(self) -> Any:
return encode_to_dict(self.data)

def to_json(self, *, indent: int = 4, sort_keys: bool = True) -> str:
"""Object as JSON."""
return json.dumps(self.to_dict(), indent=indent, sort_keys=sort_keys)

def __eq__(self, other: object) -> bool:
if isinstance(other, self.__class__):
return self.to_json() == other.to_json()
if isinstance(other, (dict, list)):
return self.to_dict() == other
return False

def __hash__(self) -> int:
return hash(self.to_json(indent=0))

def __ne__(self, other: object) -> bool:
return not self == other


class GenericHelperFn(AWSHelperFn):
"""Used as a fallback for the template generator"""

def __init__(self, data: Any):
self.data = self.getdata(data)

def to_dict(self) -> Any:
return encode_to_dict(self.data)


class Base64(AWSHelperFn):
def __init__(self, data: Any) -> None:
Expand Down

0 comments on commit b8e4e29

Please sign in to comment.