JSON assertions.

This commit is contained in:
John Chilton
2023-02-02 10:52:02 -05:00
parent d427883f28
commit 90e4648320
4 changed files with 152 additions and 1 deletions
@@ -9,7 +9,7 @@ from galaxy.util import unicodify
log = logging.getLogger(__name__)
assertion_module_names = ["text", "tabular", "xml", "hdf5", "archive", "size"]
assertion_module_names = ["text", "tabular", "xml", "json", "hdf5", "archive", "size"]
# Code for loading modules containing assertion checking functions, to
# create a new module of assertion functions, create the needed python
@@ -0,0 +1,53 @@
import json
from typing import (
Any,
Callable,
cast,
)
PropertyVisitor = Callable[[str, Any], Any]
def any_in_tree(f: PropertyVisitor, json_tree: Any):
if isinstance(json_tree, list):
for element in json_tree:
if any_in_tree(f, element):
return True
elif isinstance(json_tree, dict):
for key, value in json_tree.items():
if f(cast(str, key), value):
return True
elif any_in_tree(f, value):
return True
return False
def assert_has_json_property_with_value(
output,
property: str,
value: str,
):
"""Assert JSON tree contains the specified property with specified JSON-ified value."""
output_json = json.loads(output)
expected_value = json.loads(value)
def is_property(key, value):
return key == property and value == expected_value
assert any_in_tree(is_property, output_json), f"Failed to find property [{property}] with JSON value [{value}]"
def assert_has_json_property_with_text(
output,
property: str,
text: str,
):
"""Assert JSON tree contains the specified property with specified JSON-ified value."""
output_json = json.loads(output)
def is_property(key, value):
return key == property and value == text
assert any_in_tree(is_property, output_json), f"Failed to find property [{property}] with text [{text}]"
+59
View File
@@ -2070,6 +2070,7 @@ module.
<xs:group ref="TestAssertionsTabular" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsArchive" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsXml" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsJson" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsH5" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:complexType>
@@ -2126,6 +2127,15 @@ module.
<xs:element name="element_text" type="AssertElementText"/>
</xs:choice>
</xs:group>
<xs:group name="TestAssertionsJson">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[Assertions for JSON data]]></xs:documentation>
</xs:annotation>
<xs:choice>
<xs:element name="has_json_property_with_value" type="AssertHasJsonPropertyWithValue"/>
<xs:element name="has_json_property_with_text" type="AssertHasJsonPropertyWithText"/>
</xs:choice>
</xs:group>
<xs:group name="TestAssertionsH5">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[Assertions for H5 data]]></xs:documentation>
@@ -2356,6 +2366,7 @@ $attribute_list::5
<xs:group ref="TestAssertionsGeneral" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsText" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsTabular" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsJson" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsXml" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="TestAssertionsH5" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
@@ -2607,6 +2618,46 @@ $attribute_list::5
<xs:attributeGroup ref="AssertAttributePath"/>
<xs:attributeGroup ref="AssertAttributeNegate"/>
</xs:complexType>
<xs:complexType name="AssertHasJsonPropertyWithValue">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Asserts the JSON document contains a property or key with the specified JSON value.
```xml
<has_json_property_with_value property="skipped_columns" value="[1, 3, 5]" />
```
$attribute_list::5
]]>
</xs:documentation>
</xs:annotation>
<xs:attributeGroup ref="AssertAttributeProperty"/>
<xs:attribute name="value" type="xs:string" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">JSON-ified value to search for. This will be converted from an XML string to JSON with Python's json.loads function.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="AssertHasJsonPropertyWithText">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Asserts the JSON document contains a property or key with the specified text (i.e. string) value.
```xml
<has_json_property_with_text property="color" text="red" />
```
$attribute_list::5
]]>
</xs:documentation>
</xs:annotation>
<xs:attributeGroup ref="AssertAttributeProperty"/>
<xs:attribute name="text" type="xs:string" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">Text value to search for.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="AssertHasH5Keys">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
@@ -2659,6 +2710,14 @@ $attribute_list::5
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="AssertAttributeProperty">
<xs:attribute name="property" type="xs:string" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">JSON property to search the target for.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="AssertAttributeNegate">
<xs:attribute name="negate" type="PermissiveBoolean" default="false">
<xs:annotation>
@@ -216,6 +216,18 @@ XML_XML_ELEMENT = """
</assert_contents>
"""
JSON_HAS_PROPERTY_WITH_VALUE = """
<assert_contents>
<has_json_property_with_value property="{property}" value="{value}" />
</assert_contents>
"""
JSON_HAS_PROPERTY_WITH_WITH = """
<assert_contents>
<has_json_property_with_text property="{property}" text="{text}" />
</assert_contents>
"""
VALID_XML = """<root>
<elem name="foo">
<more name="bar">BAR</more>
@@ -227,6 +239,9 @@ VALID_XML = """<root>
"""
INVALID_XML = '<root><elem name="foo"></root>'
VALID_SIMPLE_JSON = """{"foo": 5, "list": [{"textprop": "right"}]}"""
if h5py is not None:
with tempfile.NamedTemporaryFile(delete=False) as tmp:
h5name = tmp.name
@@ -693,6 +708,26 @@ TESTS = [
lambda x: "Text of element with path './/more': Did not expect text matching expression '(BA[RZ]|QUX)$' in output ('BAR')"
in x,
),
(
JSON_HAS_PROPERTY_WITH_VALUE.format(property="foo", value="5"),
VALID_SIMPLE_JSON,
lambda x: len(x) == 0,
),
(
JSON_HAS_PROPERTY_WITH_VALUE.format(property="foo", value="6"),
VALID_SIMPLE_JSON,
lambda x: "Failed to find property [foo] with JSON value [6]" in x,
),
(
JSON_HAS_PROPERTY_WITH_WITH.format(property="textprop", text="right"),
VALID_SIMPLE_JSON,
lambda x: len(x) == 0,
),
(
JSON_HAS_PROPERTY_WITH_WITH.format(property="textprop", text="wrong"),
VALID_SIMPLE_JSON,
lambda x: "Failed to find property [textprop] with text [wrong]" in x,
),
# test has_archive_member with zip
(
ARCHIVE_HAS_ARCHIVE_MEMBER.format(path="(\\./)?testdir/file1.txt", content_assert="", all="false"),
@@ -988,6 +1023,10 @@ TEST_IDS = [
"xml_element failure (due to n)",
"xml_element failure (due to min/max in combination with negate)",
"xml_element failure (due to subassertion)",
"has_json_property_with_value success",
"has_json_property_with_value failure",
"has_json_property_with_text success",
"has_json_property_with_text failure",
"has_archive_member zip",
"has_archive_member tar",
"has_archive_member non-archive",