//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 30 Jul 08 Brian Frank Creation
//
using syntax
using fwt
class DocTest : Test
{
//////////////////////////////////////////////////////////////////////////
// Basic Text Handling
//////////////////////////////////////////////////////////////////////////
Void testEmpty()
{
doc := makeDoc("")
verifyEq(doc.text, "")
verifyEq(doc.charCount, 0)
verifyEq(doc.lineCount, 1)
verifyEq(doc.lineAtOffset(0), 0)
verifyEq(doc.offsetAtLine(0), 0)
verifyEq(doc.textRange(0,0), "")
}
Void testOne()
{
doc := makeDoc("x")
verifyEq(doc.text, "x")
verifyEq(doc.charCount, 1)
verifyEq(doc.lineCount, 1)
verifyEq(doc.lineAtOffset(0), 0)
verifyEq(doc.lineAtOffset(1), 0)
verifyEq(doc.offsetAtLine(0), 0)
verifyEq(doc.textRange(0,1), "x")
}
Void testTwo()
{
doc := makeDoc("xy")
verifyEq(doc.text, "xy")
verifyEq(doc.charCount, 2)
verifyEq(doc.lineCount, 1)
verifyEq(doc.lineAtOffset(0), 0)
verifyEq(doc.lineAtOffset(1), 0)
verifyEq(doc.offsetAtLine(0), 0)
verifyEq(doc.textRange(0,2), "xy")
verifyEq(doc.textRange(0,1), "x")
verifyEq(doc.textRange(1,1), "y")
}
Void testTwoLines()
{
doc := makeDoc("x\ny")
verifyEq(doc.text, "x\ny")
verifyEq(doc.charCount, 3)
verifyEq(doc.lineCount, 2)
verifyEq(doc.offsetAtLine(0), 0)
verifyEq(doc.offsetAtLine(1), 2)
verifyEq(doc.lineAtOffset(0), 0)
verifyEq(doc.lineAtOffset(1), 0)
verifyEq(doc.lineAtOffset(2), 1)
verifyEq(doc.textRange(0,1), "x")
verifyEq(doc.textRange(0,2), "x\n")
verifyEq(doc.textRange(0,3), "x\ny")
verifyEq(doc.textRange(1,1), "\n")
verifyEq(doc.textRange(1,2), "\ny")
verifyEq(doc.textRange(2,1), "y")
}
Void testThreeLines()
{
doc := makeDoc("abc\nd\nef")
verifyEq(doc.text, "abc\nd\nef")
verifyEq(doc.charCount, 8)
verifyEq(doc.lineCount, 3)
verifyEq(doc.offsetAtLine(0), 0)
verifyEq(doc.offsetAtLine(1), 4)
verifyEq(doc.offsetAtLine(2), 6)
verifyEq(doc.lineAtOffset(0), 0)
verifyEq(doc.lineAtOffset(1), 0)
verifyEq(doc.lineAtOffset(3), 0)
verifyEq(doc.lineAtOffset(4), 1)
verifyEq(doc.lineAtOffset(5), 1)
verifyEq(doc.lineAtOffset(6), 2)
verifyText(doc, "abc\nd\nef")
}
Void testReplaceBasic()
{
doc := makeDoc("")
doc.modify(0, 0, "y"); verifyText(doc, "y")
doc.modify(0, 0, "x"); verifyText(doc, "xy")
doc.modify(2, 0, "z"); verifyText(doc, "xyz")
doc.modify(1, 0, "!"); verifyText(doc, "x!yz")
doc.modify(1, 1, ""); verifyText(doc, "xyz")
doc.modify(0, 3, "a\nb\nc"); verifyText(doc, "a\nb\nc")
doc.modify(2, 1, "x"); verifyText(doc, "a\nx\nc")
doc.modify(1, 1, ""); verifyText(doc, "ax\nc")
doc.modify(4, 0, "\nd\ne"); verifyText(doc, "ax\nc\nd\ne")
doc.modify(3, 2, "#"); verifyText(doc, "ax\n#d\ne")
doc.modify(3, 2, ""); verifyText(doc, "ax\n\ne")
doc.modify(2, 2, "q"); verifyText(doc, "axqe")
doc.modify(1, 3, "\nfoo\nbar"); verifyText(doc, "a\nfoo\nbar")
doc.modify(3, 2, "x\ny"); verifyText(doc, "a\nfx\ny\nbar")
doc.modify(0, 0, "\n"); verifyText(doc, "\na\nfx\ny\nbar")
doc.modify(11, 0, "\nw"); verifyText(doc, "\na\nfx\ny\nbar\nw")
doc.modify(0, 13, ""); verifyText(doc, "")
}
Void testReplaceRand()
{
doc := makeDoc("")
text := ""
20.times
{
newText := randLines(1..5)
start := Int.random(0..doc.size)
len := Int.random(0..doc.size).min(doc.size-start)
text = text[0..<start] + newText + text[start+len..-1]
doc.modify(start, len, newText)
verifyText(doc, text)
}
}
//////////////////////////////////////////////////////////////////////////
// Tabs
//////////////////////////////////////////////////////////////////////////
Void testTabsWithoutConv()
{
options := TextEditorOptions()
{
tabSpacing = 2
convertTabsToSpaces = false
}
doc := makeDoc("x\ty\t\tz\n\tabc", options)
verifyEq(doc.line(0), "x\ty\t\tz")
verifyEq(doc.line(1), "\tabc")
doc.modify(0, 0, "\t")
verifyEq(doc.line(0), "\tx\ty\t\tz")
doc.modify(doc.offsetAtLine(1)+2, 0, "\t\t")
verifyEq(doc.line(1), "\ta\t\tbc")
}
Void testTabsWithConv()
{
options := TextEditorOptions()
{
tabSpacing = 2
convertTabsToSpaces = true
}
doc := makeDoc("x\ty\t\tz\n\tabc", options)
//__|_|_|_|
verifyEq(doc.line(0), "x y z")
verifyEq(doc.line(1), " abc")
doc.modify(0, 0, "\t")
verifyEq(doc.line(0), " x y z")
doc.modify(doc.offsetAtLine(1)+3, 0, "\t\t")
//__|_|_|_|
verifyEq(doc.line(1), " a bc")
}
Void testTabsConvertToSpaces()
{
verifySame(Parser.convertTabsToSpaces("a b c d", 2), "a b c d")
verifyEq(Parser.convertTabsToSpaces("\t{}", 2), " {}")
verifyEq(Parser.convertTabsToSpaces(" \t{}", 2), " {}")
verifyEq(Parser.convertTabsToSpaces("\t\t{}", 2), " {}")
verifyEq(Parser.convertTabsToSpaces("\t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces(" \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces(" \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces(" \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces(" \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces("\t\t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces("\t \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces("\t \t{}", 4), " {}")
verifyEq(Parser.convertTabsToSpaces("\t \t{}", 4)," {}")
}
//////////////////////////////////////////////////////////////////////////
// Bracket Matching
//////////////////////////////////////////////////////////////////////////
Void testMatchBracket()
{
// basic
// 01234567
s := "<{[()]}>"
doc := makeDoc(s)
verifyMatchBracket(doc, 0, 7)
verifyMatchBracket(doc, 1, 6)
verifyMatchBracket(doc, 2, 5)
verifyMatchBracket(doc, 3, 4)
// spanning multiple lines
// 0 12 34 56 78 90 12 34
s = "<\n{\n[\n(\n)\n]\n}\n>"
doc = makeDoc(s)
verifyMatchBracket(doc, 0, 14)
verifyMatchBracket(doc, 2, 12)
verifyMatchBracket(doc, 4, 10)
verifyMatchBracket(doc, 6, 8)
// nested
// 0 12 34 56 78 90 12 34
s = "}\n{\n{\n{\n}\n}\n}\n{"
doc = makeDoc(s)
verifyEq(doc.matchBracket(0), null)
verifyEq(doc.matchBracket(14), null)
verifyMatchBracket(doc, 2, 12)
verifyMatchBracket(doc, 4, 10)
verifyMatchBracket(doc, 6, 8)
}
Void verifyMatchBracket(Doc doc, Int a, Int b)
{
verifyEq(doc.matchBracket(a), b)
verifyEq(doc.matchBracket(b), a)
}
//////////////////////////////////////////////////////////////////////////
// Find
//////////////////////////////////////////////////////////////////////////
Void testFind()
{
doc := makeDoc("")
doc.text =
//0123456789_123456789_
"Hello there, x foo!
Thing xyz foo! foo!
And that is all."
verifyEq(doc.findNext("th", 0, true), 6)
verifyEq(doc.findNext("Th", 0, true), 20)
verifyEq(doc.findNext("Th", 0, false), 6)
verifyEq(doc.findNext("TH", 0, true), null)
verifyEq(doc.findNext("TH", 0, false), 6)
verifyEq(doc.findNext("THING", 0, true), null)
verifyEq(doc.findNext("THING", 0, false), 20)
verifyEq(doc.findNext("foo", 0, true), 15)
verifyEq(doc.findNext("foo", 16, true), 30)
verifyEq(doc.findNext("foo", 32, true), 35)
verifyEq(doc.findNext("foo", 36, true), null)
verifyEq(doc.findNext("Foo", 0, true), null)
verifyEq(doc.findNext("Foo", 0, false), 15)
verifyEq(doc.findNext("Foo", 16, false), 30)
verifyEq(doc.findNext("FOO", 32, false), 35)
verifyEq(doc.findNext("fOO", 36, false), null)
verifyEq(doc.findPrev("foo", 99, true), 35)
verifyEq(doc.findPrev("foo", 34, true), 30)
verifyEq(doc.findPrev("foo", 29, true), 15)
verifyEq(doc.findPrev("foo", 14, true), null)
verifyEq(doc.findPrev("FOO", 99, true), null)
verifyEq(doc.findPrev("FOO", 99, false), 35)
verifyEq(doc.findPrev("fOo", 34, false), 30)
verifyEq(doc.findPrev("Foo", 29, false), 15)
verifyEq(doc.findPrev("foO", 14, false), null)
/* don't support mult-line find right now
verifyEq(doc.findNext("oo!\nThing", 0, false), 16)
verifyEq(doc.findNext("oo!\nThinx", 0, false), null)
*/
}
//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////
Str randLines(Range numLines)
{
text := ""
Int.random(numLines).times
{
line := "abcdefghijklmnopqrstuvwxyz"[0..<Int.random(0..25)] + "\n"
text += line
}
return text[0..-2]
}
Doc makeDoc(Str text, TextEditorOptions options := TextEditorOptions.load)
{
doc := Doc(options,
SyntaxRules {})
doc.text = text
return doc
}
Void verifyText(Doc doc, Str text)
{
verifyEq(doc.text, text)
// try every offset to end
lineIndex := 0
text.size.times |Int s|
{
// ranges
(text.size-s).times |Int i|
{
verifyEq(doc.textRange(s,i), text[s..<s+i])
}
// test line at offset
verifyEq(doc.lineAtOffset(s), lineIndex)
if (text[s] == '\n') lineIndex++
}
// try every single one char
text.size.times |Int i|
{
verifyEq(doc.textRange(i, 1), text[i..i])
}
}
}