hyf

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

fixture_assertions.mojo (8564B)


      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"]
     68             .string_value()
     69             .find(expected["message_contains"].string_value())
     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() and rhs.is_int() and lhs.int_value() == rhs.int_value()
    185         )
    186 
    187     if lhs.is_float() or rhs.is_float():
    188         return (
    189             lhs.is_float()
    190             and rhs.is_float()
    191             and lhs.float_value() == rhs.float_value()
    192         )
    193 
    194     if lhs.is_string() or rhs.is_string():
    195         return (
    196             lhs.is_string()
    197             and rhs.is_string()
    198             and lhs.string_value() == rhs.string_value()
    199         )
    200 
    201     if lhs.is_array() or rhs.is_array():
    202         if not lhs.is_array() or not rhs.is_array():
    203             return False
    204         var lhs_items = lhs.array_items()
    205         var rhs_items = rhs.array_items()
    206         if len(lhs_items) != len(rhs_items):
    207             return False
    208         for i in range(len(lhs_items)):
    209             if not _json_values_equal(lhs_items[i], rhs_items[i]):
    210                 return False
    211         return True
    212 
    213     if lhs.is_object() or rhs.is_object():
    214         if not lhs.is_object() or not rhs.is_object():
    215             return False
    216         var rhs_keys = rhs.object_keys()
    217         if len(lhs.object_keys()) != len(rhs_keys):
    218             return False
    219         for key in rhs_keys:
    220             if not _has_key(lhs, key):
    221                 return False
    222             if not _json_values_equal(lhs[key], rhs[key]):
    223                 return False
    224         return True
    225 
    226     return dumps(lhs) == dumps(rhs)
    227 
    228 
    229 def _assert_json_equal(actual: Value, expected: Value) raises:
    230     if expected.is_null():
    231         assert_true(actual.is_null())
    232         return
    233 
    234     if expected.is_bool():
    235         assert_true(actual.is_bool())
    236         assert_equal(actual.bool_value(), expected.bool_value())
    237         return
    238 
    239     if expected.is_int():
    240         assert_true(actual.is_int())
    241         assert_equal(Int(actual.int_value()), Int(expected.int_value()))
    242         return
    243 
    244     if expected.is_float():
    245         assert_true(actual.is_float())
    246         assert_equal(actual.float_value(), expected.float_value())
    247         return
    248 
    249     if expected.is_string():
    250         assert_true(actual.is_string())
    251         assert_equal(actual.string_value(), expected.string_value())
    252         return
    253 
    254     if expected.is_array():
    255         assert_true(actual.is_array())
    256         var actual_items = actual.array_items()
    257         var expected_items = expected.array_items()
    258         assert_equal(len(actual_items), len(expected_items))
    259         for i in range(len(expected_items)):
    260             _assert_json_equal(actual_items[i], expected_items[i])
    261         return
    262 
    263     if expected.is_object():
    264         assert_true(actual.is_object())
    265         var expected_keys = expected.object_keys()
    266         assert_equal(len(actual.object_keys()), len(expected_keys))
    267         for key in expected_keys:
    268             assert_true(_has_key(actual, key))
    269             _assert_json_equal(actual[key], expected[key])
    270         return
    271 
    272     assert_equal(dumps(actual), dumps(expected))
    273 
    274 
    275 def _has_key(value: Value, key: String) -> Bool:
    276     for candidate in value.object_keys():
    277         if candidate == key:
    278             return True
    279     return False