Files
sml-projects/test/normal-move-tests.sml
2026-01-15 12:32:13 +00:00

2144 lines
65 KiB
Standard ML

structure NormalMoveTests =
struct
open Railroad
open Railroad.Test
open InputMsg
fun getChr (app: AppType.app_type) =
let
val {cursorIdx, buffer, ...} = app
val c = LineGap.substring (cursorIdx, 1, buffer)
in
String.sub (c, 0)
end
val hMove = describe "move motion 'h'"
[ test "moves cursor left by one when cursorIdx > 0 and is not on a newline"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 1)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"h")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test "does not move cursor when cursor is already at index 0" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\nworld\n"
val app = AppWith.idx (app, 0)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"h")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test
"moves cursor to char before a newline\
\ when there is just one newline to the left"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\nworld\n"
val app = AppWith.idx (app, 6)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"h")
in
(* assert *)
Expect.isTrue (cursorIdx = 4)
end)
, test
"moves cursor past first newline immediately following \
\a non-newline character"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\nworld\n"
val app = AppWith.idx (app, 7)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"h")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
, test
"moves cursor past newline when we see, to the left, \
\ a newline with a chr prior to it"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\nworld\n"
val app = AppWith.idx (app, 6)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"h")
in
(* assert *)
Expect.isTrue (cursorIdx = 4)
end)
, test "moves cursor to a newline when newline is not preceded by char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "\n\n\nhello\n"
val app = AppWith.idx (app, 3)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"h")
val app2 = TestUtils.update (app1, CHAR_EVENT #"h")
val app3 = TestUtils.update (app2, CHAR_EVENT #"h")
val app4 = TestUtils.update (app3, CHAR_EVENT #"h")
(* assert *)
val c1 = #cursorIdx app1 = 2
val c2 = #cursorIdx app2 = 1
val c3 = #cursorIdx app3 = 0
val c4 = #cursorIdx app4 = 0
in
Expect.isTrue (c1 andalso c2 andalso c3 andalso c4)
end)
]
val lMove = describe "move motion 'l'"
[ test "moves cursor right by one when cursorIdx < length" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val {cursorIdx = oldCursorIdx, ...} = app
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (oldCursorIdx = 0 andalso cursorIdx = 1)
end)
, test
"does not move cursor when cursorIdx is at end of buffer \
\and last char is a newline preceded by a newline"
(fn _ =>
let
(* arrange *)
val str = "hello world\n\n"
val initialCursorIdx = String.size str - 1
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (cursorIdx = initialCursorIdx)
end)
, test
"does not move cursor when cursorIdx is at end of buffer \
\and last char is a non-newline preceded by a non-newline"
(fn _ =>
let
(* arrange *)
val str = "hello world"
val initialCursorIdx = String.size str - 1
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (cursorIdx = initialCursorIdx)
end)
, test
"does not move cursor when cursorIdx is at end of buffer \
\and last char is a newline preceded by a non-newline"
(fn _ =>
let
(* arrange *)
val str = "hello world\n"
val initialCursorIdx = String.size str - 2
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (cursorIdx = initialCursorIdx)
end)
, test "moves cursor to char past newline when newline is preceded by char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\nworld\n"
val app = AppWith.idx (app, 4)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
, test "moves cursor to second newline when newline is preceded by char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\nworld\n"
val app = AppWith.idx (app, 4)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"l")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
, test
"moves cursor to each newline without skipping when no newline \
\is preceded by char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "\n\n\nhello\n"
val app = AppWith.idx (app, 0)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"l")
val app2 = TestUtils.update (app1, CHAR_EVENT #"l")
val app3 = TestUtils.update (app2, CHAR_EVENT #"l")
val app4 = TestUtils.update (app3, CHAR_EVENT #"l")
(* assert *)
val c1 = #cursorIdx app1 = 1
val c2 = #cursorIdx app2 = 2
val c3 = #cursorIdx app3 = 3
val c4 = #cursorIdx app4 = 4
in
Expect.isTrue (c1 andalso c2 andalso c3 andalso c4)
end)
]
val jMove = describe "move motion 'j'"
[ test "moves cursur down one column when column = 0" (fn _ =>
let
(* arrange *)
(* "world" at end of string is intentionally misspelled as "qorld"
* since "world" appears twice and it is useful to differentiate them
* *)
val app = TestUtils.init "hello \nworld \ngoodbye \nqorld \n"
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"j")
val app2 = TestUtils.update (app1, CHAR_EVENT #"j")
val app3 = TestUtils.update (app2, CHAR_EVENT #"j")
(* assert *)
val c1 = getChr app1 = #"w"
val c2 = getChr app2 = #"g"
val c3 = getChr app3 = #"q"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "moves cursur down one column when column = 1" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello \nworld \nbye \nfriends \n"
val app = AppWith.idx (app, 1)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"j")
val app2 = TestUtils.update (app1, CHAR_EVENT #"j")
val app3 = TestUtils.update (app2, CHAR_EVENT #"j")
(* assert *)
val c1 = getChr app1 = #"o"
val c2 = getChr app2 = #"y"
val c3 = getChr app3 = #"r"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "moves cursur down one column when column = 2" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello \nworld \nbye \nfriends \n"
val app = AppWith.idx (app, 2)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"j")
val app2 = TestUtils.update (app1, CHAR_EVENT #"j")
val app3 = TestUtils.update (app2, CHAR_EVENT #"j")
(* assert *)
val c1 = getChr app1 = #"r"
val c2 = getChr app2 = #"e"
val c3 = getChr app3 = #"i"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test
"moves to last char on below column \
\when cursor is on a column that is greater than \
\the number of columns on the next line"
(fn _ =>
let
(* arrange *)
val str =
"hello world!\n\
\bye!\n"
val app = TestUtils.init str
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"j")
(* assert *)
val c1 = getChr app = #"!"
in
Expect.isTrue c1
end)
, test "when next newline is preceded by char, goes to idx after newline"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\nworld\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
, test "moves to same column on last line after a count" (fn _ =>
let
(* arrange *)
val str =
"let\n\
\hello\n\
\in\n\
\0\n\
\end\n"
val app = TestUtils.init str
val app1 = AppWith.idx (app, 0)
val app2 = AppWith.idx (app, 1)
val app3 = AppWith.idx (app, 2)
(* act *)
val newApp1 = TestUtils.updateMany (app1, "4j")
val newApp2 = TestUtils.updateMany (app2, "4j")
val newApp3 = TestUtils.updateMany (app3, "4j")
(* assert *)
val c1 = getChr newApp1 = #"e"
val c2 = getChr newApp2 = #"n"
val c3 = getChr newApp3 = #"d"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "leaves cursor at same idx when on the last line" (fn _ =>
let
(* arrange *)
val str = "hello \nworld \ntime to go\n\n"
val app = TestUtils.init str
val initialCursorIdx = String.size str - 1
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
in
(* assert *)
Expect.isTrue (cursorIdx = initialCursorIdx)
end)
, test "goes to next idx when cursor is on a newline" (fn _ =>
let
(* arrange *)
val str = "hello\n\nworld\n"
val app = TestUtils.init str
val app = AppWith.idx (app, 6)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
in
(* assert *)
Expect.isTrue (cursorIdx = 7)
end)
, test
"goes to second-last newline in file \
\when newline is preceded by a non-newline"
(fn _ =>
let
(* arrange *)
val str = "hello\nworld\n"
val initialCursorIdx = 4
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
(* assert *)
val expectedIdx = 10
in
Expect.isTrue (cursorIdx = expectedIdx)
end)
, test
"goes to last newline in file \
\when newline is preceded by another newline"
(fn _ =>
let
(* arrange *)
val str = "hello\n\nworld\n\n"
val initialCursorIdx = String.size str - 5
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
(* assert *)
val expectedIdx = String.size str - 1
in
Expect.isTrue (cursorIdx = expectedIdx)
end)
, test "goes to last line in file when last char is not a newline" (fn _ =>
let
(* arrange *)
val str = "hello\nworld"
val initialCursorIdx = 0
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
(* assert *)
val expectedIdx = 6
in
Expect.isTrue (cursorIdx = expectedIdx)
end)
, test
"leaves cursor at same idx when on last line \
\and file ends with a non-newline"
(fn _ =>
let
(* arrange *)
val str = "hello\nworld"
val initialCursorIdx = 6
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"j")
(* assert *)
val expectedIdx = initialCursorIdx
in
Expect.isTrue (cursorIdx = expectedIdx)
end)
, test
"does not go to last chr in file \
\when last chr is a newline preceded by a non-newline \
\and a count is provided"
(fn _ =>
let
(* arrange *)
val str = "hello\nworld\n"
val initialCursorIdx = 0
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.updateMany (app, "2j")
(* assert *)
val expectedIdx = 6
in
Expect.isTrue (cursorIdx = expectedIdx)
end)
]
val kMove = describe "move motion 'k'"
[ test "moves cursur up one column when column = 0" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "0__\n4___\n9___\n14_\n"
val app = AppWith.idx (app, 14)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"k")
val app2 = TestUtils.update (app1, CHAR_EVENT #"k")
val app3 = TestUtils.update (app2, CHAR_EVENT #"k")
(* assert *)
val c1 = getChr app1 = #"9"
val c2 = getChr app2 = #"4"
val c3 = getChr app3 = #"0"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "moves cursur up one column when column = 1" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "_w_\n_5__\n_10_\n_15\n"
val app = AppWith.idx (app, 15)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"k")
val app2 = TestUtils.update (app1, CHAR_EVENT #"k")
val app3 = TestUtils.update (app2, CHAR_EVENT #"k")
(* assert *)
val c1 = getChr app1 = #"1"
val c2 = getChr app2 = #"5"
val c3 = getChr app3 = #"w"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "moves cursur up one column when column = 2" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "__2\n__6\n__10\n__15\n"
val app = AppWith.idx (app, 15)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"k")
val app2 = TestUtils.update (app1, CHAR_EVENT #"k")
val app3 = TestUtils.update (app2, CHAR_EVENT #"k")
(* assert *)
val c1 = getChr app1 = #"1"
val c2 = getChr app2 = #"6"
val c3 = getChr app3 = #"2"
in
Expect.isTrue (c1 andalso c2 andalso c3)
end)
, test "goes to last newline when there are two newlines preceding cursor"
(fn _ =>
let
(* arrange *)
val str = "hello\n\n world\n"
val app = TestUtils.init str
val app = AppWith.idx (app, 7)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"k")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
, test "leaves cursor at same idx when already on first line" (fn _ =>
let
(* arrange *)
val str = "hello \nworld \ntime to go\n"
val app = TestUtils.init str
(* line below does nothing; just for explicitness *)
val app = AppWith.idx (app, 0)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"k")
(* assert *)
val isAtStart = cursorIdx = 0
in
Expect.isTrue isAtStart
end)
, test
"goes to last column of previous line when cursor is \
\on a column greater than the number of columns in the previous line"
(fn _ =>
let
(* arrange *)
val str =
"hello world\n\
\now a quite long line is next\n"
val app = TestUtils.init str
val app = AppWith.idx (app, String.size str - 2)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"k")
in
(* assert *)
Expect.isTrue (cursorIdx = 10)
end)
, test
"when the previous newline is preceded by a non-newline, \
\jumps past newline"
(fn _ =>
let
(* arrange *)
val str = "hello\n\nworld\n"
val app = TestUtils.init str
val app = AppWith.idx (app, 6)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"k")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test
"when file ends with two newlines, \
\and cursor is on second-last newline, \
\we should be able to move up by one line"
(fn _ =>
let
(* arrange *)
val str = "hello\nworld\n\n"
val app = TestUtils.init str
val app = AppWith.idx (app, 12)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"k")
in
(* assert *)
Expect.isTrue (cursorIdx = 6)
end)
]
val wMove = describe "move motion 'w'"
[ test "moves cursor to start of next word in contiguous string" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val chr = String.sub ("hello world", cursorIdx)
in
Expect.isTrue (chr = #"w")
end)
, test
"moves cursor to first char-after-newline \
\when cursor is on last word of line \
\and there is another line after this one"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello \n\n\n world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"w")
in
(* assert *)
Expect.isTrue (cursorIdx = 7)
end)
, test "does not break on undescore when cursor is on alphanumeric char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello_world goodbye_world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"g")
end)
, test "breaks on punctuation when cursor is on alphanumeric char" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "hello, world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #",")
end)
, test "breaks on alphanumeric char when cursor is on punctuation" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "!#%^()hello\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"h")
end)
, test "breaks on non-blank char when on blank char" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "0123 \t \n \t 789\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"7")
end)
, test "moves cursor to first alphanumeric char when on punctuation"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "!!! hello\n"
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val startsAtExc = getChr app = #"!"
val movedToH = getChr app1 = #"h"
in
Expect.isTrue (startsAtExc andalso movedToH)
end)
, test "moves cursor to last char when cursor is on last word" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val chrIsEnd = getChr app = #"d"
in
Expect.isTrue chrIsEnd
end)
, test
"moves cursor to second newline when cursor is on the last word \
\and the file ends with two newlines"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\n"
val app = AppWith.idx (app, 0)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 6)
end)
, test
"does not move to or past newline when cursor is on last word \
\and text ends with newline"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n"
val app = AppWith.idx (app, 0)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 4)
end)
, test "moves cursor to character after newline" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\nworld\nagain\n"
val app = AppWith.idx (app, 0)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 6)
end)
]
val WMove = describe "move motion 'W'"
[ test "moves cursor to start of next WORD in contiguous string" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"W")
(* assert *)
val chr = String.sub ("hello world", cursorIdx)
in
Expect.isTrue (chr = #"w")
end)
, test
"moves cursor to first char-after-newline \
\when cursor is on last word of line \
\and there is another line after this one"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello \n\n\n world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"W")
in
(* assert *)
Expect.isTrue (cursorIdx = 7)
end)
, test "does not break on punctuation when cursor is on alphanumeric char"
(fn _ =>
(* vi's definition of 'WORD' instead of 'word' *)
let
(* arrange *)
val app = TestUtils.init "hello, world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"W")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"w")
end)
, test "does not break on alphanumeric char when cursor is on punctuation"
(fn _ =>
(* vi's definition of 'WORD' instead of 'word' *)
let
(* arrange *)
val app = TestUtils.init "#!hello!!! world!!!\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"W")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"w")
end)
, test "moves cursor to first non-blank when cursor is on blank" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "0123 \t \n \t 789\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"7")
end)
, test "moves cursor to last char when cursor is on last word" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"w")
(* assert *)
val chrIsEnd = getChr app = #"d"
in
Expect.isTrue chrIsEnd
end)
]
val eMove = describe "move motion 'e'"
[ test
"moves cursor to last alphanumeric char in contiguous string\
\when in alphanumeric word and there is at least one\
\alphanumeric char after cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
in
(* assert *)
Expect.isTrue (getChr app = #"o")
end)
, test
"moves cursor to last punctuation char in contiguous string\
\when in punctuation word and there is at least one\
\punctuation char after cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "#$%!^ world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
in
(* assert *)
Expect.isTrue (getChr app = #"^")
end)
, test
"moves cursor to last char of next word,\
\when cursor is on last char of current word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
in
(* assert *)
Expect.isTrue (getChr app = #"d")
end)
, test "does not break on undescore when cursor is on alphanumeric char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello_world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"d")
end)
, test "breaks on undescore when cursor is on punctuation char" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "#!^*(_#!@*(\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"(")
end)
, test "breaks on punctuation when cursor is on alphanumeric char" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "hello, world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"o")
end)
, test "breaks on alphanumeric char when cursor is on punctuation" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "!#%^()hello\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #")")
end)
, test "skips past tab" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "0123 \t \t \t 789\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"9")
end)
, test
"moves cursor to last char in punctuation string \
\when cursor is on punctuation"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "!!! hello\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 2)
end)
, test "moves cursor to last char when cursor is on last word" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val chrIsEnd = getChr app = #"d"
in
Expect.isTrue chrIsEnd
end)
, test
"moves cursor to end of current word \
\when current word is last word in line"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\n\nworld\n"
val app = AppWith.idx (app, 0)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"e")
(* assert *)
val isAtEndOfHello = getChr app = #"o"
in
Expect.isTrue isAtEndOfHello
end)
]
val EMove = describe "move motion 'E'"
[ test "moves cursor to last char in WORD when in contiguous string"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hel!!!lo world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
in
(* assert *)
Expect.isTrue (getChr app = #"o")
end)
, test
"moves cursor to last char of next WORD,\
\when cursor is on last char of current WORD"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "#ELL) !@*(ORL$\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
in
(* assert *)
Expect.isTrue (getChr app = #"$")
end)
, test "does not break on punctuation when in alphanumeric char" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "hello, world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #",")
end)
, test "does not break on alphanumeric char when in punctuation" (fn _ =>
(* vi's definition of 'word' instead of 'WORD' *)
let
(* arrange *)
val app = TestUtils.init "!#%^()hello world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"o")
end)
, test "skips past tab: '\\t'" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "0123 \t \t \t 789\n"
val app = AppWith.idx (app, 4)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
(* assert *)
val cursorChr = getChr app
in
Expect.isTrue (cursorChr = #"9")
end)
, test "moves cursor to last char when cursor is on last word" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world!\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"E")
in
(* assert *)
Expect.isTrue (getChr app = #"!")
end)
]
val bMove = describe "move motion 'b'"
[ test "leaves cursor at 0 when cursor is already at 0" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test "moves cursor previous word when on first character of next word"
(fn _ =>
let
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 6)
val chr1 = getChr app
val app2 = TestUtils.update (app, CHAR_EVENT #"b")
val chr2 = getChr app2
in
Expect.isTrue (chr1 = #"w" andalso chr2 = #"h")
end)
, test "moves cursor to 0 when cursor > 0 and cursor is on first word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 3)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test
"moves cursor to first alphanumeric char after whitespace \
\when in alphanumeric word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " hello world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test
"moves cursor to first alphanumeric char after punctuation \
\when in alphanumeric word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "!*#hello world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test
"moves cursor to first punctuation char after whitespace \
\when in punctuation word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " !@#$%^&*()\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (getChr app = #"!")
end)
, test
"moves cursor to first punctuation char after \
\alphanumeric char when in punctuation word"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "abc!@#$%^&*()\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (getChr app = #"!")
end)
, test "stops when char preceding word is newline" (fn _ =>
let
(* arrange *)
val originalString = "hello\n\n\nworld\n"
val app = TestUtils.init originalString
val app = AppWith.idx (app, String.size originalString - 2)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"b")
in
(* assert *)
Expect.isTrue (getChr app = #"w")
end)
]
val BMove = describe "move motion 'B'"
[ test "leaves cursor at 0 when cursor is already at 0" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test "moves cursor to 0 when cursor > 0 and cursor is on first WORD"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 3)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test
"moves cursor to first non-space char after whitespace \
\when in WORD"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " hello world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test
"moves cursor to 0 when cursor is on first letter of first WORD \
\and there are leadinng spaces before first letter"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " hello world\n"
val app = AppWith.idx (app, 3)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test
"moves cursor to first char in WORD \
\when in alphanumeric word preceded by punctuation"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "!*#hello world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (getChr app = #"!")
end)
, test "moves cursor to first char after whitespace when in WORD" (fn _ =>
let
(* arrange *)
val app = TestUtils.init " !qwerty@#$%^&*()\n"
val app = AppWith.idx (app, 17)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (getChr app = #"!")
end)
, test
"moves cursor to first char in WORD \
\when in punctuation word preceded by alphanumeric"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "abc!@#$%^&*()\n"
val app = AppWith.idx (app, 11)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"B")
in
(* assert *)
Expect.isTrue (getChr app = #"a")
end)
]
val zeroMove = describe "move motion '0'"
[ test "moves cursor to 0 when on first line" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello w7rld\n"
val app = AppWith.idx (app, 7)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"0")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test "leaves cursor on 0 when cursor is already on 0" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"0")
in
(* assert *)
Expect.isTrue (cursorIdx = 0)
end)
, test "leaves cursor at same idx when cursor is on '\\n'" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n hello again\n"
val app = AppWith.idx (app, 11)
val {cursorIdx = oldIdx, ...} = app
(* act *)
val {cursorIdx = newIdx, ...} =
TestUtils.update (app, CHAR_EVENT #"0")
in
(* assert *)
Expect.isTrue (oldIdx = newIdx)
end)
, test
"moves cursor to first char after newline when cursor is after first line"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n#ello again\n"
val app = AppWith.idx (app, 21)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"0")
(* assert *)
val chr = getChr app
in
(* assert *)
Expect.isTrue (chr = #"#")
end)
, test "leaves cursor at same idx when on last newline" (fn _ =>
let
(* arrange *)
val str =
"hello\n\
\\n\
\\n\
\world\n\
\\n\
\\n"
val initialCursorIdx = String.size str - 1
val app = TestUtils.init str
val app = AppWith.idx (app, initialCursorIdx)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"0")
(* assert *)
val expectedIdx = initialCursorIdx
in
(* assert *)
Expect.isTrue (cursorIdx = expectedIdx)
end)
]
val dlrMove = describe "move motion '$'"
[ test "moves cursor to char before '\\n' in contiguous string" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello wor9\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"$")
in
(* assert *)
Expect.isTrue (getChr app = #"9")
end)
, test
"leaves cursor at same idx in contiguous string\
\when char after cursor is '\\n'"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n world\n"
val app = AppWith.idx (app, 11)
val oldIdx = #cursorIdx app
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"$")
val newIdx = #cursorIdx app
val nchr = getChr app
val nchr = Char.toString nchr ^ "\n"
in
(* assert *)
Expect.isTrue (oldIdx = newIdx)
end)
, test "does not move cursor when cursor is on a newline" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n\nworld\n"
val app = AppWith.idx (app, 6)
val oldIdx = #cursorIdx app
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"$")
val newIdx = #cursorIdx app
val nchr = getChr app
val nchr = Char.toString nchr ^ "\n"
in
(* assert *)
Expect.isTrue (oldIdx = newIdx)
end)
]
val hatMove = describe "move motion '^'"
[ test
"moves cursor to first non-space char in first line\
\when first line starts with spaces\
\and cursor is on first space"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " 3ello world\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"^")
in
(* assert *)
Expect.isTrue (getChr app = #"3")
end)
, test
"moves cursor to first non-space char in first line\
\when first line starts with space\
\and cursor is after first non-space char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init " 3ell7 world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"^")
in
(* assert *)
Expect.isTrue (getChr app = #"3")
end)
, test
"moves cursor to first non-space char\
\when cursor is after first line\
\and before first non-space char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n world\n"
val app = AppWith.idx (app, 7)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"^")
in
(* assert *)
Expect.isTrue (getChr app = #"w")
end)
, test
"moves cursor to first non-space char\
\when cursor is after first line\
\and after first non-space char"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello\n world\n"
val app = AppWith.idx (app, 11)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"^")
in
(* assert *)
Expect.isTrue (getChr app = #"w")
end)
, test "leaves cursor in same position when on '\\n'" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hel\nlo\n"
val app = AppWith.idx (app, 3)
val oldIdx = #cursorIdx app
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"^")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = oldIdx)
end)
]
val GMove = describe "move motion 'G'"
[ test
"moves cursor to second last char in buffer, \
\if last char is a newline preced by a non-newline"
(fn _ =>
(* Note: We assume unix-style line endings:
* End of file always has \n at the end. *)
let
(* arrange *)
val str = "01234\n56789\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 2)
end)
, test
"moves cursor to last char in buffer, \
\if last char is a newline and second-last char is also a newline"
(fn _ =>
let
(* arrange *)
val str = "01234\n5678\n\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 1)
end)
, test
"moves cursor to last char in buffer, \
\if last char is not a newline and second-last char \
\is also not a newline"
(fn _ =>
let
(* arrange *)
val str = "01234\n5678\n\n"
val app = TestUtils.init str
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"G")
in
(* assert *)
Expect.isTrue (#cursorIdx app = String.size str - 1)
end)
]
val percentMove = describe "move motion '%'"
[ test "moves to next ) when cursor is on (" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(hello)\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #")")
end)
, test "moves to preceding ( when cursur is on )" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(hello)\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"(")
end)
(* testing that cursor goes to correct level of nesting *)
, test "moves to outermost ) when cursor is on outermost (" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 10)
end)
, test "moves to outermost ( when cursor is on outermost )" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 0)
end)
, test "moves to middle ) when cursor is on middle (" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
val app = AppWith.idx (app, 1)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 9)
end)
, test "moves to middle ( when cursor is on middle )" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
val app = AppWith.idx (app, 9)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 1)
end)
, test "moves to innermost ) when cursor is on innermost (" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
val app = AppWith.idx (app, 2)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 8)
end)
, test "moves to innermost ( when cursor is on innermost )" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "(((hello)))\n"
val app = AppWith.idx (app, 8)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = 2)
end)
(* testing different pair combinations *)
, test "moves to next ] when cursor is on [" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "[hello]\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"]")
end)
, test "moves to preceding [ when cursur is on ]" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "[hello]\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"[")
end)
, test "moves to next } when cursor is on {" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "{hello}\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"}")
end)
, test "moves to preceding { when cursur is on }" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "{hello}\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"{")
end)
, test "moves to next > when cursor is on <" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "<hello>\n"
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #">")
end)
, test "moves to preceding < when cursur is on >" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "<hello>\n"
val app = AppWith.idx (app, 6)
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (getChr app = #"<")
end)
, test
"does not move when cursor is on a non-pair-character, \
\and there is no pair-character where the cursor is at or after the cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "he()o, world\n"
val app = AppWith.idx (app, 5)
val oldIdx = #cursorIdx app
(* act *)
val app = TestUtils.update (app, CHAR_EVENT #"%")
val newIdx = #cursorIdx app
in
(* assert *)
Expect.isTrue (newIdx = oldIdx)
end)
, test
"moves cursor when the cursor is not on a \
\pair-character, but there is a pair-character \
\after the cursor"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "he()o world\n"
val app = AppWith.idx (app, 0)
(* act *)
val {cursorIdx, ...} = TestUtils.update (app, CHAR_EVENT #"%")
in
(* assert *)
Expect.isTrue (cursorIdx = 3)
end)
]
(* movements which use multiple chars *)
fun updateMany (app, str) =
let
fun loop (pos, app) =
if pos = String.size str then
app
else
let
val chr = String.sub (str, pos)
val app = TestUtils.update (app, CHAR_EVENT chr)
in
loop (pos + 1, app)
end
in
loop (0, app)
end
val tMove = describe "move motion 't'"
[ test
"motion 'td' moves cursor to char before 'd' in string \"hello world\""
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = updateMany (app, "td")
in
(* assert *)
Expect.isTrue (getChr app = #"l")
end)
, test "repeating 't' motion with same char does not move cursor" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app1 = updateMany (app, "td")
val app2 = updateMany (app1, "td")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2 andalso getChr app1 = #"l")
end)
, test
"does not move cursor at all when char following 't' is not in string"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app1 = updateMany (app, "t;")
in
(* assert *)
Expect.isTrue (#cursorIdx app1 = #cursorIdx app)
end)
, test "is cancellable by pressing escape" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"t")
val app2 = TestUtils.update (app1, KEY_ESC)
(* should not move cursor like other 't' tests do *)
val app3 = TestUtils.update (app2, CHAR_EVENT #"d")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2
andalso #cursorIdx app2 = #cursorIdx app3)
end)
]
val TMove = describe "move motion 'T'"
[ test
"motion 'Th' moves cursor to char after 'h' in string \"hello world\""
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = updateMany (app, "Th")
in
(* assert *)
Expect.isTrue (getChr app = #"e")
end)
, test "repeating 'T' motion with same char does not move cursor" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app1 = updateMany (app, "Te")
val app2 = updateMany (app1, "Te")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2 andalso getChr app1 = #"l")
end)
, test
"does not move cursor at all when char following 'T' is not in string"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app1 = updateMany (app, "T;")
in
(* assert *)
Expect.isTrue (#cursorIdx app1 = #cursorIdx app)
end)
, test "is cancellable by pressing escape" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"T")
val app2 = TestUtils.update (app1, KEY_ESC)
(* should ordinarily move cursor to 'w' but in this case should not
* as escape key should cancel motion which was in progress *)
val app3 = TestUtils.update (app2, CHAR_EVENT #" ")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2
andalso #cursorIdx app2 = #cursorIdx app3)
end)
]
val fMove = describe "move motion 'f'"
[ test "motion 'fw' moves cursor to first 'w' in string \"hello world\""
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = updateMany (app, "fw")
in
(* assert *)
Expect.isTrue (getChr app = #"w")
end)
, test "count followed by f<char> moves forwards to count'th match" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = updateMany (app, "3fl")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 9 andalso getChr app = #"l")
end)
, test
"'count f<char>' goes to last match when count is greater than number of chars"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = updateMany (app, "9fl")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 9 andalso getChr app = #"l")
end)
, test
"does not move cursor at all when char following 'f' is not in string"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app1 = updateMany (app, "f;")
in
(* assert *)
Expect.isTrue (#cursorIdx app1 = #cursorIdx app)
end)
, test "is cancellable by pressing escape" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"f")
val app2 = TestUtils.update (app1, KEY_ESC)
val app3 = TestUtils.update (app2, CHAR_EVENT #"d")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2
andalso #cursorIdx app2 = #cursorIdx app3)
end)
]
val FMove = describe "move motion 'F'"
[ test "motion 'Fe' moves cursor to first 'e' before cursor" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = updateMany (app, "Fe")
in
(* assert *)
Expect.isTrue (getChr app = #"e")
end)
, test "count followed by F<char> moves backwards to count'th match"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = updateMany (app, "3Fl")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 2 andalso getChr app = #"l")
end)
, test
"'count F<char>' goes to first match when count is greater than number of chars"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = updateMany (app, "9Fl")
in
(* assert *)
Expect.isTrue (#cursorIdx app = 2 andalso getChr app = #"l")
end)
, test
"does not move cursor at all when char following 'F' is not in string"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app1 = updateMany (app, "F;")
in
(* assert *)
Expect.isTrue (#cursorIdx app1 = #cursorIdx app)
end)
, test "is cancellable by pressing escape" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"F")
val app2 = TestUtils.update (app1, KEY_ESC)
val app3 = TestUtils.update (app2, CHAR_EVENT #"r")
in
(* assert *)
Expect.isTrue
(#cursorIdx app1 = #cursorIdx app2
andalso #cursorIdx app2 = #cursorIdx app3)
end)
]
val ggMove = describe "move motion 'gg'"
[ test "moves cursor to start when cursor is at end" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 10)
(* act *)
val app = updateMany (app, "gg")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test "moves cursor to start when cursor is in middle" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 5)
(* act *)
val app = updateMany (app, "gg")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test "leaves cursor in same place when cursor is already at start"
(fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
(* act *)
val app = updateMany (app, "gg")
in
(* assert *)
Expect.isTrue (getChr app = #"h")
end)
, test "is cancellable by pressing escape" (fn _ =>
let
(* arrange *)
val app = TestUtils.init "hello world\n"
val app = AppWith.idx (app, 5)
(* act *)
val app1 = TestUtils.update (app, CHAR_EVENT #"g")
val app2 = TestUtils.update (app1, KEY_ESC)
val app3 = TestUtils.update (app2, CHAR_EVENT #"g")
in
(* assert *)
Expect.isTrue (#cursorIdx app3 = 5)
end)
]
val tests =
[ hMove
, jMove
, kMove
, lMove
, wMove
, WMove
, bMove
, BMove
, eMove
, EMove
, zeroMove
, dlrMove
, hatMove
, GMove
, percentMove
(* multi-char motions *)
, tMove
, TMove
, fMove
, FMove
, ggMove
]
end