diff options
Diffstat (limited to 'tests/check.py')
| -rw-r--r-- | tests/check.py | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/tests/check.py b/tests/check.py index 7e23d94..dcbda5e 100644 --- a/tests/check.py +++ b/tests/check.py @@ -89,6 +89,14 @@ DIAGNOSTICS = [ ('input m = message by key { a: u32 }\nview v = m.a\n', '2:10', "fields of 'm' are only available in its handler"), ('state x = 0\ninput m = message by key { a: bytes }\non m {\n x = m.a\n}\n', '4:7', 'expected a number, not bytes'), ('input m = message by key { a: u32 }\non m {\n reply m.z\n}\n', '3:9', "message 'm' has no field 'z'"), + ('input m = message {\n g: {\n a: text\n }\n}\non m {\n reply m.g\n}\n', '7:9', + "'m.g' is a group of fields; read one of them, as in m.g.a"), + ('input m = message {\n g: {\n a: text\n }\n}\non m {\n reply m.g.b\n}\n', '7:9', "message 'm' has no field 'g.b'"), + ('input m = message {\n g: text\n g: {\n a: text\n }\n}\n', '3:3', "duplicate field 'g'"), + ('input m = message {\n g: {\n a: text\n }\n g: {\n b: text\n }\n}\n', '5:3', "duplicate field 'g'"), + ('input m = message {\n g: {\n }\n}\n', '3:3', "the group 'g' has no fields"), + ('input m = message {\n group_of_things: {\n another_long_name: text\n }\n}\n', '3:5', + "'group_of_things.another_long_name' is longer than 31 characters"), ('state x = 0\non frame {\n require x.bytes\n}\n', '3:11', "a number has no 'bytes'"), ('state d: bytes by key\nstate e: bytes by key\n', '2:7', 'at most one keyed collection is allowed'), ('state d: bytes by key\ninput m = message by key { a: bytes }\non m {\n d[key].replace(0 .. m.a, m.a)\n}\n', '4:23', @@ -1156,17 +1164,44 @@ input add = message { input count = message { n: u32 } +record Shipment { + title: text + city: text + note: text + zip = 0 +} +state shipped: list of Shipment +input ship = message { + title: text + to: { + city: text + zip: u32 + door: { + note: text + } + } +} on add { notes.add(Note { title: add.title, body: add.body, points: add.points }) reply add.title } on count { counted = counted + count.n } +on ship { + shipped.append(Shipment { title: ship.title, city: ship.to.city, note: ship.to.door.note, zip: ship.to.zip }) + reply ship.to.door.note +} view counted_view = counted view all = each n in notes { title = n.title body = n.body points = n.points } +view shipments = each s in shipped { + title = s.title + city = s.city + note = s.note + zip = s.zip +} """ @@ -1240,9 +1275,46 @@ def server_json(aup, pure, work, rounds=300): assert post('/inputs/add', b'plain', json_body=False)[:2] == (400, 'json') # two text fields need JSON assert post('/inputs/count', b'{"n": -1}')[:2] == (400, 'json_type') assert post('/inputs/count', b'{"n": 4294967296}')[:2] == (400, 'json_type') + # Groups: objects inside the body, members in any order, strings + # read where they are (escaped ones unescaped over themselves). + shipments = [] + for _ in range(rounds // 3): + title, city, note = (''.join(rng.choice(pieces) for _ in range(rng.randint(0, 5))) for _ in range(3)) + zip_code = rng.randint(0, 99999) + door = [('note', note)] + to = [('city', city), ('zip', zip_code), ('door', dict(door))] + rng.shuffle(to) + members = [('title', title), ('to', dict(to))] + rng.shuffle(members) + text = json.dumps(dict(members), ensure_ascii=rng.random() < 0.5) + got = post('/inputs/ship', text.encode()) + assert got == (200, 'none', note.encode()), (text, got) + shipments.append({'title': title, 'city': city, 'note': note, 'zip': zip_code}) + # A group's fixed field from the query, by its path. + assert post('/inputs/ship?to.zip=7', b'{"title": "q", "to": {"city": "c", "door": {"note": "n"}}}')[:2] == \ + (200, 'none') + shipments.append({'title': 'q', 'city': 'c', 'note': 'n', 'zip': 7}) + rows = json.loads(http(host.port, 'GET', f'/views/shipments?count={len(shipments)}')[3])['items'] + assert rows == shipments, [(a, b) for a, b in zip(rows, shipments) if a != b][:2] + grouped = '{"title": "t", "to": {"city": "c", "zip": 1, "door": {"note": "n"}}}' + wrong_groups = [ + (grouped.replace('"zip": 1', '"zip": 1, "lat": 2'), 'json_field'), # unknown member of a group + (grouped.replace('"note": "n"', '"note": "n", "bell": {"x": 1}'), 'json_field'), + (grouped.replace('"door": {"note": "n"}', '"door": "n"'), 'json_type'), # a group as a value + (grouped.replace('"title": "t"', '"title": {"a": "t"}'), 'json_type'), # a field as a group + (grouped.replace('"door": {"note": "n"}', '"door": {}'), 'missing_field'), + (grouped.replace('"zip": 1', '"zip": 1, "zip": 2'), 'json_field'), + (grouped.replace('"zip": 1', '"zip": [1]'), 'json_type'), + (grouped.replace('"zip": 1', '"zip": null'), 'json_type'), + (grouped.replace('"note": "n"', '"note": "n\\ud800"'), 'json'), + (grouped.replace('"door": {"note": "n"}}', '"door": {"note": "n"}'), 'json'), # unclosed + ] + for body, error in wrong_groups: + assert post('/inputs/ship', body.encode())[:2] == (400, error), (body, post('/inputs/ship', body.encode())) + assert post('/inputs/ship?to.zip=7', grouped.encode())[:2] == (400, 'json_field') # given twice finally: host.stop() - return rounds + len(wrong) + return rounds + len(wrong) + rounds // 3 + len(wrong_groups) BEAT_SOURCE = """state beats = 0 |
