aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 04:42:05 +0100
committereunhhu <[email protected]>2026-10-19 04:42:05 +0100
commit096a70a7cd5a5785b1b52aa8512422b30f014c09 (patch)
tree5d0632f6dccfdd5d83da709b2e8212ab9d1a0451 /tests
parent5f223bd45d9279982ec6e4ca334c089c07782639 (diff)
downloadaup-096a70a7cd5a5785b1b52aa8512422b30f014c09.tar.gz
aup-096a70a7cd5a5785b1b52aa8512422b30f014c09.zip
Bytes alone as a state (Pure 028): state x: bytes (= "..." its UTF-8), held as a text state is and written to the module as type 6, its name read as a bytes value and x = ... setting it whole (a string meets bytes), cursors and marks in it, its insert and remove, its start and end refused with a bytes state's diagnostic, a text never set from it; test bytes_state (300 steps of random bytes with 0x00 and 0xff added and cut, started again from the store 15 times, against Python; the same name as a text from the store and by a replace: UTF-8 bytes kept, others anew, and back to bytes what the text held), three diagnostics; the 60 sources the same modules; 002
Diffstat (limited to 'tests')
-rw-r--r--tests/check.py69
1 files changed, 69 insertions, 0 deletions
diff --git a/tests/check.py b/tests/check.py
index b999262..fc08708 100644
--- a/tests/check.py
+++ b/tests/check.py
@@ -83,6 +83,11 @@ DIAGNOSTICS = [
('record R {\n v = 0\n}\ninput m = message { d: bytes }\nstate t: text\non m {\n let xs: list of R\n'
' t = text(bytes(xs))\n}\n', '8:18', 'bytes(...) makes bytes of a list of i64, not of R'),
('state x = 0\nview v = [1, 2]\n', '2:10', "a list's elements begin a let's list"),
+ # Bytes alone as a state (Pure 028): read and set whole, no cursor in it, no text set from it.
+ ('state data: bytes\nstate at: cursor in data\n', '2:7', "a cursor moves in a text state; 'data' is not one"),
+ ('state data: bytes\ninput k = key KeyK\non k.down {\n data.insert(data.start, "x")\n}\n', '4:3',
+ "'data' is a bytes state: it is read and set whole, no cursor in it"),
+ ('state data: bytes\nstate t: text\ninput k = key KeyK\non k.down {\n t = data\n}\n', '5:7', 'expected text, not bytes'),
# Lets' lists in inner blocks and xs = [...] (after 140's inflate): a stored list is not given elements so.
('record R {\n v = 0\n}\nstate rs: list of R\non frame {\n rs = []\n}\n', '6:3',
"a list changes by append, insert, remove, rs[index].field = value and (a let's) rs = [...]"),
@@ -666,6 +671,22 @@ view inner {
}
'''
+BYTES_STATE = '''state data: bytes
+state n = 0
+input add = message { d: bytes }
+input cut = message { k: u32 }
+on add {
+ data = data + add.d
+ n = data.bytes
+}
+on cut {
+ require cut.k <= data.bytes
+ data = data[0 .. cut.k]
+ n = data.bytes
+}
+view whole = data
+'''
+
ACCEPTED = [
# Views of any value (Pure 027's 4e): a list as it is, filtered, a map with a list and a bytes column, a list a body
# built, bytes.
@@ -1583,6 +1604,53 @@ def nested_values(aup, pure_run, work):
+def bytes_state(aup, pure_run, work, steps=300):
+ """Bytes alone as a state (Pure 028): random bytes (0x00 and 0xff among them) added and cut, the app started again
+ from its store every so often, each step's state and view against Python's; then the same name as a text: a start
+ from the store and a replace while running keep bytes that are UTF-8 and start anew from bytes that are not, and
+ going back to bytes finds what the text held."""
+ import random
+ import struct
+ path = work / 'bytes_state.pmod'
+ (work / 'bytes_state.aup').write_text(BYTES_STATE)
+ compile_module(aup, work / 'bytes_state.aup', path)
+ text_path = work / 'bytes_as_text.pmod'
+ (work / 'bytes_as_text.aup').write_text('state data: text\nstate n = 0\nview whole = data\n')
+ compile_module(aup, work / 'bytes_as_text.aup', text_path)
+ rng = random.Random(28)
+ store, model, starts = work / 'bytes-store', b'', 0
+ for segment in range(steps // 20):
+ commands, wanted = '', []
+ for _ in range(20):
+ if rng.random() < 0.7:
+ d = bytes(rng.choice(b'a\x00\xff\xc3\xa9') for _ in range(rng.randrange(0, 5)))
+ commands += f"message add {d.hex() or '-'}\n"
+ model += d
+ wanted.append((model, 'none'))
+ else:
+ k = rng.randrange(0, len(model) + 3)
+ commands += f"message cut {struct.pack('<I', k).hex()}\n"
+ if k <= len(model): model = model[:k]
+ wanted.append((model, 'none' if k <= len(model) or k == len(model) else 'limit'))
+ lines = run(pure_run, path, '--store', store, stdin=commands, check=False).stdout.splitlines()
+ starts += 1
+ assert len(lines) == len(wanted), (segment, len(lines))
+ for (data, _), line in zip(wanted, lines):
+ state = json.loads(line)
+ assert state['states']['data'] == data.hex() == state['views']['whole'] and state['states']['n'] == len(data), (data, state)
+ # The same name as a text, from the store: UTF-8 bytes kept, others anew (the values record says it was bytes).
+ for given in (b'ok \xc3\xa9', b'no \xff'):
+ store = work / f'bytes-store-{given[0]:02x}'
+ run(pure_run, path, '--store', store, stdin=f"message add {given.hex()}\n")
+ shown = json.loads(run(pure_run, text_path, '--store', store, stdin='show\n').stdout.splitlines()[-1])
+ assert shown['states']['data'] == (given.decode() if given[0] == 0x6f else ''), shown
+ back = json.loads(run(pure_run, path, '--store', store, stdin='show\n').stdout.splitlines()[-1])
+ assert back['states']['data'] == (given.hex() if given[0] == 0x6f else ''), back # what the text held, stored
+ replaced = json.loads(run(pure_run, path, stdin=f"message add {given.hex()}\nreplace {text_path}\nshow\n").stdout.splitlines()[-1])
+ assert replaced['states']['data'] == (given.decode() if given[0] == 0x6f else ''), replaced
+ return {'steps': steps, 'starts': starts}
+
+
def inner_lists(aup, pure_run, work, events=100):
"""Lets' lists in inner blocks, and xs = [...] (after 140's inflate): a let's list in a for's block, a keyed one, one
in a fn's for and one in a view's body begin empty each time their let is run; xs = [...] empties a let's list and
@@ -2801,6 +2869,7 @@ def main():
report['bare_lists'] = bare_lists(aup, pure_run, work)
report['bytes_compared'] = bytes_compared(aup, pure_run, work)
report['inner_lists'] = inner_lists(aup, pure_run, work)
+ report['bytes_state'] = bytes_state(aup, pure_run, work)
report['stored_nested'] = stored_nested(aup, pure_run, work, range(6))
report['documents'] = documents_model(aup, pure_run, work, range(4))
print(json.dumps(report))