aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-30 06:41:41 +0100
committereunhhu <[email protected]>2026-09-30 06:41:41 +0100
commitc69682e1f1bc73e2b1f4a22b8eb3ec463be588e3 (patch)
treec181b50fedf6b306b4a53d06d305d4be24bcb94e /tests
parentaa279fb959024134416fc33f90f648d8332e9af4 (diff)
downloadaup-c69682e1f1bc73e2b1f4a22b8eb3ec463be588e3.tar.gz
aup-c69682e1f1bc73e2b1f4a22b8eb3ec463be588e3.zip
Spread an item or a message into a record or a send, and set an item whole
Adding one field to the board two nodes share (Pure's research 105) still meant the record, the output, three sends and the code applying what the other node sent: the sends and the apply named every field. ..source, last in a record value's or a send's braces, gives the fields not written from the source's fields of the same names: an item (an index, a let, the item a for walks, list[key]) or the handler's message (grouped fields by their paths). A record value gives what the source lacks its default; a send still needs every field. list[i] = Record { ... } sets every field of the item, all of them given; a keyed list's key does not change, so a value with another key fails the event (limit) and changes nothing. Both are the fields written out: the checks compare the modules byte for byte, and run the key rule in pure-run. Seven diagnostics: a spread not last, a source that is no item nor this handler's message (also another handler's message), a spread inside a send's group, a send field left empty, a whole item missing a field, a value that is no record. The board now sends { ..at } and applies cards[k] = Card { ..remote }: a new field is written in two places, the record and the output.
Diffstat (limited to 'tests')
-rw-r--r--tests/check.py42
1 files changed, 42 insertions, 0 deletions
diff --git a/tests/check.py b/tests/check.py
index 6408b05..211d508 100644
--- a/tests/check.py
+++ b/tests/check.py
@@ -58,6 +58,10 @@ ARGS = 'record T {\n a = 0\n}\nstate xs: list of T\nstate n = 0\n'
# A message with rows (a list of a record) beside a list state.
ROWS = 'record L {\n item = 0\n qty = 1\n}\nstate xs: list of L\nstate n = 0\ninput o = message {\n rows: list of L\n}\n'
# An app with an output: bought items go out as orders.
+# A keyed list, an index into it, a message and an output of the same fields: spreads and whole items.
+CARDS = ('record Card {\n title: text\n lane = 0\n note: text\n}\nstate cards: list of Card by title\n'
+ 'state at: index of cards\ninput m = message {\n title: text\n lane: u32\n note: text\n}\n'
+ 'output o = message {\n title: text\n lane: u32\n note: text\n}\n')
SENDS = ('state n = 0\ninput buy = message {\n item: text\n count: u32\n}\noutput ordered = message {\n'
' item: text\n count: u32\n to: {\n city: text\n }\n}\n')
DIAGNOSTICS = [
@@ -245,6 +249,17 @@ DIAGNOSTICS = [
('record L {\n item = 0\n}\noutput o = message {\n rows: list of L\n}\n', '5:9',
'an output sends no rows: send one message a row'),
('input a = message like nothing\n', '1:24', "'nothing' is no message input or output declared before"),
+ (CARDS + 'on m {\n cards.add(Card { ..m, title: "x" })\n}\n', '19:25', 'a spread goes last'),
+ (CARDS + 'on m {\n cards.add(Card { ..1 })\n}\n', '19:22',
+ "a spread takes an item (an index, or list[key]) or this handler's message"),
+ (CARDS + 'record Other {\n title: text\n}\nstate others: list of Other\nstate it: index of others\n'
+ 'on m {\n send o { ..it }\n}\n', '24:3', "send o needs 'lane'"),
+ (CARDS + 'on m {\n cards[m.title] = Card { title: m.title }\n}\n', '19:20', "cards[...] = Card { ... } needs 'lane'"),
+ (CARDS + 'on m {\n cards[m.title] = 1\n}\n', '19:20', "'cards' holds Card records"),
+ (CARDS + 'output g = message {\n to: {\n city: text\n }\n}\non m {\n send g { to: { ..m } }\n}\n', '24:18',
+ "a spread goes in the send's own braces, not a group's"),
+ (CARDS + 'input k = key Space\non k.down {\n cards.add(Card { ..m })\n}\n', '20:22',
+ "a spread takes an item (an index, or list[key]) or this handler's message"),
('input k = key Space\ninput a = message like k\n', '2:24', "'k' is no message input or output declared before"),
('input a = message like a\n', '1:24', "'a' is no message input or output declared before"),
('record L {\n item = 0\n}\ninput i = message {\n rows: list of L\n}\noutput o = message like i\n', '7:25',
@@ -1297,6 +1312,33 @@ def main():
compile_module(aup, work / 'liked.aup', work / 'liked.pmod'), 'message like differs from its fields written'
report['message_like'] = True
+ # A spread (..source) and a whole item (list[k] = Record { ... }) are their fields written out: the same module.
+ spreads = (CARDS + 'on m {\n if !cards.has(m.title) {\n cards.add(Card { lane: 1, ..m })\n } else {\n'
+ ' cards[m.title] = Card { ..m }\n }\n at = cards[m.title]\n send o { note: "x", ..at }\n'
+ ' send o { ..cards[m.title] }\n}\n')
+ written = (CARDS + 'on m {\n if !cards.has(m.title) {\n cards.add(Card { title: m.title, lane: 1, note: m.note })\n'
+ ' } else {\n require cards[m.title].title == m.title\n cards[m.title].lane = m.lane\n'
+ ' cards[m.title].note = m.note\n }\n at = cards[m.title]\n'
+ ' send o { title: at.title, lane: at.lane, note: "x" }\n'
+ ' send o { title: cards[m.title].title, lane: cards[m.title].lane, note: cards[m.title].note }\n}\n')
+ (work / 'spreads.aup').write_text(spreads)
+ (work / 'spreads-written.aup').write_text(written)
+ assert compile_module(aup, work / 'spreads.aup', work / 'spreads.pmod') == \
+ compile_module(aup, work / 'spreads-written.aup', work / 'spreads-written.pmod'), 'a spread differs from its fields'
+ # A whole item keeps its key: one that names another fails its event, and changes nothing.
+ (work / 'whole.aup').write_text('record T {\n name: text\n n = 0\n}\nstate ts: list of T by name\n'
+ 'input make = key KeyM\ninput right = key KeyR\ninput wrong = key KeyW\n'
+ 'on make.down { ts.add(T { name: "a", n: 1 }) }\n'
+ 'on right.down { ts["a"] = T { name: "a", n: 5 } }\n'
+ 'on wrong.down { ts["a"] = T { name: "b", n: 7 } }\n'
+ 'view total = sum(t.n for t in ts)\nview count = ts.count\n')
+ compile_module(aup, work / 'whole.aup', work / 'whole.pmod')
+ shown = [json.loads(line) for line in run(pure_run, work / 'whole.pmod', stdin='down make\ndown wrong\ndown right\n',
+ check=False).stdout.splitlines()]
+ assert [(v['views']['total'], v['fault'], v['error']) for v in shown] == \
+ [(1, 'none', None), (1, 'limit', 'event failed'), (5, 'none', None)], shown
+ report['spreads'] = True
+
# Replacing a running module keeps states by name.
compile_module(aup, ROOT / 'examples/counter.aup', work / 'counter.pmod')
(work / 'counter2.aup').write_text('state bonus = 7\nstate count = 100\ninput tap = key Space\n'