hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

fixture_assertions.mojo (8592B)


      1 from std.testing import assert_equal, assert_true
      2 
      3 from json import Value, dumps, loads
      4 
      5 from fixture_loader import (
      6     load_fixture_scenario_expected,
      7     load_fixture_scenario_request,
      8 )
      9 
     10 
     11 def load_scenario_request(relative_path: String) raises -> Value:
     12     return load_fixture_scenario_request(relative_path)
     13 
     14 
     15 def load_scenario_request_json(relative_path: String) raises -> String:
     16     return _compact_json(load_scenario_request(relative_path))
     17 
     18 
     19 def status_request_with_invalid_version_json() raises -> String:
     20     var request = load_scenario_request("scenarios/status_ok.json")
     21     request.set("version", Value(2))
     22     return _compact_json(request)
     23 
     24 
     25 def assert_matches_scenario_response(
     26     actual: Value, relative_path: String
     27 ) raises:
     28     var expected = load_fixture_scenario_expected(relative_path)
     29 
     30     if _has_key(expected, "ok"):
     31         _assert_json_equal(actual["ok"], expected["ok"])
     32 
     33     if _has_key(expected, "equals"):
     34         var equals = expected["equals"]
     35         for path in equals.object_keys():
     36             _assert_json_equal(
     37                 _require_path(actual, path, "equals"), equals[path]
     38             )
     39 
     40     if _has_key(expected, "contains_all"):
     41         var contains_all = expected["contains_all"]
     42         for path in contains_all.object_keys():
     43             _assert_contains_all(
     44                 _require_path(actual, path, "contains_all"),
     45                 contains_all[path],
     46             )
     47 
     48     if _has_key(expected, "present_paths"):
     49         for path in expected["present_paths"].array_items():
     50             assert_true(
     51                 _path_exists(actual, path.string_value()),
     52                 "expected present path '" + path.string_value() + "'",
     53             )
     54 
     55     if _has_key(expected, "absent_paths"):
     56         for path in expected["absent_paths"].array_items():
     57             assert_true(
     58                 not _path_exists(actual, path.string_value()),
     59                 "expected absent path '" + path.string_value() + "'",
     60             )
     61 
     62     if _has_key(expected, "error_code"):
     63         _assert_json_equal(actual["error"]["code"], expected["error_code"])
     64 
     65     if _has_key(expected, "message_contains"):
     66         assert_true(
     67             actual["error"]["message"].string_value().find(
     68                 expected["message_contains"].string_value()
     69             )
     70             >= 0
     71         )
     72 
     73 
     74 def _lookup_path(value: Value, dotted_path: String) raises -> Value:
     75     var current = value.copy()
     76     for token in dotted_path.split("."):
     77         var token_string = String(token)
     78         if current.is_array():
     79             var items = current.array_items()
     80             current = items[Int(token_string)].copy()
     81         else:
     82             current = loads(current.get(token_string))
     83     return current^
     84 
     85 
     86 def _require_path(
     87     value: Value, dotted_path: String, section: String
     88 ) raises -> Value:
     89     try:
     90         return _lookup_path(value, dotted_path)
     91     except:
     92         raise Error(
     93             "missing "
     94             + section
     95             + " path '"
     96             + dotted_path
     97             + "' in actual response"
     98         )
     99 
    100 
    101 def _path_exists(value: Value, dotted_path: String) -> Bool:
    102     try:
    103         _ = _lookup_path(value, dotted_path)
    104         return True
    105     except:
    106         return False
    107 
    108 
    109 def _compact_json(value: Value) raises -> String:
    110     if value.is_null() or value.is_bool() or value.is_int() or value.is_float():
    111         return dumps(value)
    112 
    113     if value.is_string():
    114         return dumps(Value(value.string_value()))
    115 
    116     if value.is_array():
    117         var result = String("[")
    118         var items = value.array_items()
    119         for index in range(len(items)):
    120             if index > 0:
    121                 result += ","
    122             result += _compact_json(items[index])
    123         result += "]"
    124         return result^
    125 
    126     if value.is_object():
    127         var result = String("{")
    128         var first = True
    129         for key in value.object_keys():
    130             if not first:
    131                 result += ","
    132             first = False
    133             result += dumps(Value(String(key)))
    134             result += ":"
    135             result += _compact_json(value[key])
    136         result += "}"
    137         return result^
    138 
    139     return dumps(value)
    140 
    141 
    142 def _assert_contains_all(actual: Value, expected_subset: Value) raises:
    143     if expected_subset.is_array():
    144         assert_true(actual.is_array())
    145         var actual_items = actual.array_items()
    146         for expected_item in expected_subset.array_items():
    147             var found = False
    148             for actual_item in actual_items:
    149                 if _json_values_equal(actual_item, expected_item):
    150                     found = True
    151                     break
    152             assert_true(
    153                 found,
    154                 "expected array item missing: " + dumps(expected_item),
    155             )
    156         return
    157 
    158     if expected_subset.is_object():
    159         assert_true(actual.is_object())
    160         for key in expected_subset.object_keys():
    161             assert_true(
    162                 _has_key(actual, key),
    163                 "expected object key '" + key + "'",
    164             )
    165             _assert_contains_all(actual[key], expected_subset[key])
    166         return
    167 
    168     _assert_json_equal(actual, expected_subset)
    169 
    170 
    171 def _json_values_equal(lhs: Value, rhs: Value) raises -> Bool:
    172     if lhs.is_null() or rhs.is_null():
    173         return lhs.is_null() and rhs.is_null()
    174 
    175     if lhs.is_bool() or rhs.is_bool():
    176         return (
    177             lhs.is_bool()
    178             and rhs.is_bool()
    179             and lhs.bool_value() == rhs.bool_value()
    180         )
    181 
    182     if lhs.is_int() or rhs.is_int():
    183         return (
    184             lhs.is_int()
    185             and rhs.is_int()
    186             and lhs.int_value() == rhs.int_value()
    187         )
    188 
    189     if lhs.is_float() or rhs.is_float():
    190         return (
    191             lhs.is_float()
    192             and rhs.is_float()
    193             and lhs.float_value() == rhs.float_value()
    194         )
    195 
    196     if lhs.is_string() or rhs.is_string():
    197         return (
    198             lhs.is_string()
    199             and rhs.is_string()
    200             and lhs.string_value() == rhs.string_value()
    201         )
    202 
    203     if lhs.is_array() or rhs.is_array():
    204         if not lhs.is_array() or not rhs.is_array():
    205             return False
    206         var lhs_items = lhs.array_items()
    207         var rhs_items = rhs.array_items()
    208         if len(lhs_items) != len(rhs_items):
    209             return False
    210         for i in range(len(lhs_items)):
    211             if not _json_values_equal(lhs_items[i], rhs_items[i]):
    212                 return False
    213         return True
    214 
    215     if lhs.is_object() or rhs.is_object():
    216         if not lhs.is_object() or not rhs.is_object():
    217             return False
    218         var rhs_keys = rhs.object_keys()
    219         if len(lhs.object_keys()) != len(rhs_keys):
    220             return False
    221         for key in rhs_keys:
    222             if not _has_key(lhs, key):
    223                 return False
    224             if not _json_values_equal(lhs[key], rhs[key]):
    225                 return False
    226         return True
    227 
    228     return dumps(lhs) == dumps(rhs)
    229 
    230 
    231 def _assert_json_equal(actual: Value, expected: Value) raises:
    232     if expected.is_null():
    233         assert_true(actual.is_null())
    234         return
    235 
    236     if expected.is_bool():
    237         assert_true(actual.is_bool())
    238         assert_equal(actual.bool_value(), expected.bool_value())
    239         return
    240 
    241     if expected.is_int():
    242         assert_true(actual.is_int())
    243         assert_equal(Int(actual.int_value()), Int(expected.int_value()))
    244         return
    245 
    246     if expected.is_float():
    247         assert_true(actual.is_float())
    248         assert_equal(actual.float_value(), expected.float_value())
    249         return
    250 
    251     if expected.is_string():
    252         assert_true(actual.is_string())
    253         assert_equal(actual.string_value(), expected.string_value())
    254         return
    255 
    256     if expected.is_array():
    257         assert_true(actual.is_array())
    258         var actual_items = actual.array_items()
    259         var expected_items = expected.array_items()
    260         assert_equal(len(actual_items), len(expected_items))
    261         for i in range(len(expected_items)):
    262             _assert_json_equal(actual_items[i], expected_items[i])
    263         return
    264 
    265     if expected.is_object():
    266         assert_true(actual.is_object())
    267         var expected_keys = expected.object_keys()
    268         assert_equal(len(actual.object_keys()), len(expected_keys))
    269         for key in expected_keys:
    270             assert_true(_has_key(actual, key))
    271             _assert_json_equal(actual[key], expected[key])
    272         return
    273 
    274     assert_equal(dumps(actual), dumps(expected))
    275 
    276 
    277 def _has_key(value: Value, key: String) -> Bool:
    278     for candidate in value.object_keys():
    279         if candidate == key:
    280             return True
    281     return False