Closed priamai closed 1 year ago
You question isn't really clear, I'm afraid. Most matchers can take nested matchers in addition to literal values, so I expect what you want is possible, but I'd need a little more information to help. Do you have an object whose property is a list, or is list of objects with properties?
This might be better asked on Stack Overflow.
Hello @brunns, yes apologies, let me do a concrete example to explain. I have an object type that has an inner attribute of type dict.
I just want to be able to compare the internal representation (it's a dict in a property called _inner) and nothing else to assume that two objects are equal.
Right now I do this:
assert_that(stix_obj, equal_to(return_obj))
The STIX object looks like this
The test fails with this two pairs of objects:
{"type": "intrusion-set", "spec_version": "2.1", "id": "intrusion-set--ed69450a-f067-4b51-9ba2-c4616b9a6713", "created": "2016-08-08T15:50:10.983Z", "modified": "2016-08-08T15:50:10.983Z", "name": "APT BPP", "description": "An advanced persistent threat that seeks to disrupt Branistan's election with multiple attacks.", "aliases": ["Bran-teaser"], "first_seen": "2016-01-08T12:50:40.123Z", "goals": ["Disrupt the BPP", "Influence the Branistan election"], "resource_level": "government", "primary_motivation": "ideology", "secondary_motivations": ["dominance"]}
and:
{"type": "intrusion-set", "spec_version": "2.1", "id": "intrusion-set--ed69450a-f067-4b51-9ba2-c4616b9a6713", "created": "2016-08-08T15:50:10.983Z", "modified": "2016-08-08T15:50:10.983Z", "name": "APT BPP", "description": "An advanced persistent threat that seeks to disrupt Branistan's election with multiple attacks.", "aliases": ["Bran-teaser"], "first_seen": "2016-01-08T12:50:40.123Z", "goals": ["Influence the Branistan election", "Disrupt the BPP"], "resource_level": "government", "primary_motivation": "ideology", "secondary_motivations": ["dominance"]}
This is because the dictionary property called goals can have a different order of strings.
So ideally I would like to create my own comparator that only considers the dict internal representation (_inner field) and then I guess based on the value types (like the list example) ignore the order.
I hope this makes sense now.
You can compose a custom matcher for this fairly easily:
import collections
from dataclasses import dataclass
from typing import Any, Dict
from hamcrest import assert_that, contains_inanyorder, has_entries, has_property
from hamcrest.core.matcher import Matcher
@dataclass
class Stix:
_inner: Dict
def is_nonstring_sequence(candidate: Any) -> bool:
return not isinstance(candidate, str) and isinstance(candidate, collections.abc.Sequence)
def equal_to_stix(expected: Stix) -> Matcher[Stix]:
return has_property(
"_inner",
has_entries(
**{
k: (contains_inanyorder(*v) if is_nonstring_sequence(v) else v)
for k, v in expected._inner.items()
}
),
)
def test_stix_comp():
actual = Stix(
{
"type": "intrusion-set",
"spec_version": "2.1",
"id": "intrusion-set--ed69450a-f067-4b51-9ba2-c4616b9a6713",
"created": "2016-08-08T15:50:10.983Z",
"modified": "2016-08-08T15:50:10.983Z",
"name": "APT BPP",
"description": "An advanced persistent threat that seeks to disrupt Branistan's election with multiple attacks.",
"aliases": ["Bran-teaser"],
"first_seen": "2016-01-08T12:50:40.123Z",
"goals": ["Disrupt the BPP", "Influence the Branistan election"],
"resource_level": "government",
"primary_motivation": "ideology",
"secondary_motivations": ["dominance"],
}
)
expected = Stix(
{
"type": "intrusion-set",
"spec_version": "2.1",
"id": "intrusion-set--ed69450a-f067-4b51-9ba2-c4616b9a6713",
"created": "2016-08-08T15:50:10.983Z",
"modified": "2016-08-08T15:50:10.983Z",
"name": "APT BPP",
"description": "An advanced persistent threat that seeks to disrupt Branistan's election with multiple attacks.",
"aliases": ["Bran-teaser"],
"first_seen": "2016-01-08T12:50:40.123Z",
"goals": ["Influence the Branistan election", "Disrupt the BPP"],
"resource_level": "government",
"primary_motivation": "ideology",
"secondary_motivations": ["dominance"],
}
)
assert_that(actual, equal_to_stix(expected))
Assuming this does the trick.
Hi there, I am new to Hamcrest and would like to know if there is an example to override the standard object comparison equal operator. I basically have to change the list comparison for the properties of the object otherwise the default one is order dependent. Cheers.