NAME=t/undoredo
FILE=malloc://1024
CMDS=<<EOF
?e No seeks.
sH* ; ?v $$
?e

?e But try undo/redo.
sHu
sHr
sH*
sHr
sHr
sHu
sHu
sHu
sHr
sH*
?e

?e First seeks.
s 0x10 ; sH* ; ?v $$
s 0x20 ; sH* ; ?v $$
s 0x30 ; sH* ; ?v $$
s 0x40 ; sH* ; ?v $$
?e

?e Undo all seeks (and some more).
sHu ; sH* ; ?v $$ ; ?e
sHu ; sH* ; ?v $$ ; ?e
sHu ; sH* ; ?v $$ ; ?e
sHu ; sH* ; ?v $$ ; ?e
# Test if more undos break something.
sHu ; sH* ; ?v $$ ; ?e
sHu ; sH* ; ?v $$ ; ?e

?e Then redo them (and some more).
sHr ; sH* ; ?v $$ ; ?e
sHr ; sH* ; ?v $$ ; ?e
sHr ; sH* ; ?v $$ ; ?e
sHr ; sH* ; ?v $$ ; ?e
# Test if more undos break something.
sHr ; sH* ; ?v $$ ; ?e
sHr ; sH* ; ?v $$ ; ?e

?e Undo some seeks and then seek somewhere else.
sHu ; sHu
sH* ; ?v $$ ; ?e
s 0x50
sH* ; ?v $$ ; ?e
# Redo now does nothing.
sHr ; sHr ; sHr
sH* ; ?v $$ ; ?e

?e Undo all seeks again and perform a single seek with undo/redo.
sHu ; sHu ; sHu
sH* ; ?v $$ ; ?e
s 0x100
sH* ; ?v $$ ; ?e
sHu ; sHr
sH* ; ?v $$ ; ?e
EOF
EXPECT=<<EOF
No seeks.
# Current seek @ 0x0
0x0

But try undo/redo.
# Current seek @ 0x0
# Current seek @ 0x0

First seeks.
f undo_0 @ 0x0
# Current seek @ 0x10
0x10
f undo_1 @ 0x0
f undo_0 @ 0x10
# Current seek @ 0x20
0x20
f undo_2 @ 0x0
f undo_1 @ 0x10
f undo_0 @ 0x20
# Current seek @ 0x30
0x30
f undo_3 @ 0x0
f undo_2 @ 0x10
f undo_1 @ 0x20
f undo_0 @ 0x30
# Current seek @ 0x40
0x40

Undo all seeks (and some more).
f undo_2 @ 0x0
f undo_1 @ 0x10
f undo_0 @ 0x20
# Current seek @ 0x30
f redo_0 @ 0x40
0x30

f undo_1 @ 0x0
f undo_0 @ 0x10
# Current seek @ 0x20
f redo_0 @ 0x30
f redo_1 @ 0x40
0x20

f undo_0 @ 0x0
# Current seek @ 0x10
f redo_0 @ 0x20
f redo_1 @ 0x30
f redo_2 @ 0x40
0x10

# Current seek @ 0x0
f redo_0 @ 0x10
f redo_1 @ 0x20
f redo_2 @ 0x30
f redo_3 @ 0x40
0x0

# Current seek @ 0x0
f redo_0 @ 0x10
f redo_1 @ 0x20
f redo_2 @ 0x30
f redo_3 @ 0x40
0x0

# Current seek @ 0x0
f redo_0 @ 0x10
f redo_1 @ 0x20
f redo_2 @ 0x30
f redo_3 @ 0x40
0x0

Then redo them (and some more).
f undo_0 @ 0x0
# Current seek @ 0x10
f redo_0 @ 0x20
f redo_1 @ 0x30
f redo_2 @ 0x40
0x10

f undo_1 @ 0x0
f undo_0 @ 0x10
# Current seek @ 0x20
f redo_0 @ 0x30
f redo_1 @ 0x40
0x20

f undo_2 @ 0x0
f undo_1 @ 0x10
f undo_0 @ 0x20
# Current seek @ 0x30
f redo_0 @ 0x40
0x30

f undo_3 @ 0x0
f undo_2 @ 0x10
f undo_1 @ 0x20
f undo_0 @ 0x30
# Current seek @ 0x40
0x40

f undo_3 @ 0x0
f undo_2 @ 0x10
f undo_1 @ 0x20
f undo_0 @ 0x30
# Current seek @ 0x40
0x40

f undo_3 @ 0x0
f undo_2 @ 0x10
f undo_1 @ 0x20
f undo_0 @ 0x30
# Current seek @ 0x40
0x40

Undo some seeks and then seek somewhere else.
f undo_1 @ 0x0
f undo_0 @ 0x10
# Current seek @ 0x20
f redo_0 @ 0x30
f redo_1 @ 0x40
0x20

f undo_2 @ 0x0
f undo_1 @ 0x10
f undo_0 @ 0x20
# Current seek @ 0x50
0x50

f undo_2 @ 0x0
f undo_1 @ 0x10
f undo_0 @ 0x20
# Current seek @ 0x50
0x50

Undo all seeks again and perform a single seek with undo/redo.
# Current seek @ 0x0
f redo_0 @ 0x10
f redo_1 @ 0x20
f redo_2 @ 0x50
0x0

f undo_0 @ 0x0
# Current seek @ 0x100
0x100

f undo_0 @ 0x0
# Current seek @ 0x100
0x100

EOF
RUN

NAME=basic json
FILE=malloc://1024
CMDS=<<EOF
sHj
sd +10
sHj
sd +10
sHu
sHj
sHu
sHj
?e undo at the start of list
sHu
sHj
?e redo to the end
sHr; sHr
sHj
?e one more past the end
sHr
sHj
EOF
EXPECT=<<EOF
[{"offset":0,"cursor":0,"current":true}]
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":true}]
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":true},{"offset":20,"cursor":0,"current":false}]
[{"offset":0,"cursor":0,"current":true},{"offset":10,"cursor":0,"current":false},{"offset":20,"cursor":0,"current":false}]
undo at the start of list
[{"offset":0,"cursor":0,"current":true},{"offset":10,"cursor":0,"current":false},{"offset":20,"cursor":0,"current":false}]
redo to the end
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":20,"cursor":0,"current":true}]
one more past the end
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":20,"cursor":0,"current":true}]
EOF
RUN

NAME=uninitialized bug
FILE=malloc://1024
CMDS=<<EOF
sd +10
?e should produce two identical results
sd +1
sHj
sHu
sd +1
sHj
?e 0 0, or 22 23 but not 0 22
sd +10
sd +1
sHj
sHu
sd +2
sHj
EOF
EXPECT=<<EOF
should produce two identical results
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":11,"cursor":0,"current":true}]
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":11,"cursor":0,"current":true}]
0 0, or 22 23 but not 0 22
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":11,"cursor":0,"current":false},{"offset":21,"cursor":0,"current":false},{"offset":22,"cursor":0,"current":true}]
[{"offset":0,"cursor":0,"current":false},{"offset":10,"cursor":0,"current":false},{"offset":11,"cursor":0,"current":false},{"offset":21,"cursor":0,"current":false},{"offset":23,"cursor":0,"current":true}]
EOF
RUN

NAME=duplicate push
FILE=malloc://1024
CMDS=<<EOF
s 0x0
s 0x0
s 0x1
s 0x2
# shouldn't contain multiple 0 at the start
sHj
# regression test for deduplication not working on buffer edge
60sd +1
s 0x0
s 0x0
s 0x01
s 0x02
sH*~:-6..
EOF
EXPECT=<<EOF
[{"offset":0,"cursor":0,"current":false},{"offset":1,"cursor":0,"current":false},{"offset":2,"cursor":0,"current":true}]
f undo_4 @ 0x3c
f undo_3 @ 0x3d
f undo_2 @ 0x3e
f undo_1 @ 0x0
f undo_0 @ 0x1
# Current seek @ 0x2
EOF
RUN