typeset/parse_test.go

225 lines
8.1 KiB
Go
Raw Permalink Normal View History

2024-09-10 09:19:57 -06:00
package typeset
import "slices"
import "testing"
func rl (run rune) runeLayout { return runeLayout { run: run } }
func tk (kind tokenKind, value string) token {
tok := token {
kind: kind,
}
runeValue := []rune(value)
tok.runes = make([]runeLayout, len(runeValue))
for index, run := range runeValue {
tok.runes[index] = rl(run)
}
return tok
}
func compareTokens (got, correct []token) bool {
for index, tok := range got {
correctTok := correct[index]
isCorrect :=
correctTok.kind == tok.kind &&
correctTok.width == tok.width &&
slices.Equal(correctTok.runes, tok.runes)
if !isCorrect { return false }
}
return true
}
func logTokens (test *testing.T, tokens []token) {
for _, token := range tokens {
test.Logf("- %-40v | %v", token, token.runes)
}
}
func TestParseString (test *testing.T) {
// ---- processing ----
runes, tokens := parseString("hello \rworld!\nfoo\n\r\nbar\tbaz\t\tsomething")
// ---- correct data ----
correctRunes := []runeLayout {
rl('h'),
rl('e'),
rl('l'),
rl('l'),
rl('o'),
rl(' '),
rl('\r'),
rl('w'),
rl('o'),
rl('r'),
rl('l'),
rl('d'),
rl('!'),
rl('\n'),
rl('f'),
rl('o'),
rl('o'),
rl('\n'),
rl('\r'),
rl('\n'),
rl('b'),
rl('a'),
rl('r'),
rl('\t'),
rl('b'),
rl('a'),
rl('z'),
rl('\t'),
rl('\t'),
rl('s'),
rl('o'),
rl('m'),
rl('e'),
rl('t'),
rl('h'),
rl('i'),
rl('n'),
rl('g'),
}
correctTokens := []token {
tk(tokenKindWord, "hello"),
tk(tokenKindSpace, " "),
tk(tokenKindWord, "\rworld!"),
tk(tokenKindLineBreak, "\n"),
tk(tokenKindWord, "foo"),
tk(tokenKindLineBreak, "\n"),
tk(tokenKindLineBreak, "\r\n"),
tk(tokenKindWord, "bar"),
tk(tokenKindTab, "\t"),
tk(tokenKindWord, "baz"),
tk(tokenKindTab, "\t\t"),
tk(tokenKindWord, "something"),
}
// ---- testing ----
if len(runes) != len(correctRunes) {
test.Logf("len(runes) != len(correctRunes): %d, %d", len(runes), len(correctRunes))
test.Log(runes)
test.Log(correctRunes)
test.FailNow()
}
if !slices.Equal(runes, correctRunes) {
test.Log("runes != correctRunes:")
test.Log(runes)
test.Log(correctRunes)
test.FailNow()
}
if len(tokens) != len(correctTokens) {
test.Logf("len(tokens) != len(correctTokens): %d, %d", len(tokens), len(correctTokens))
test.Log("GOT")
logTokens(test, tokens)
test.Log("CORRECT")
logTokens(test, correctTokens)
test.FailNow()
}
if !compareTokens(tokens, correctTokens) {
test.Log("tokens != correctTokens:")
test.Log("GOT")
logTokens(test, tokens)
test.Log("CORRECT")
logTokens(test, correctTokens)
test.FailNow()
}
test.Logf("changing first rune from %c to x", runes[0].run)
runes[0].run = 'x'
test.Logf("first rune is now %c", runes[0].run)
tokenRune := tokens[0].runes[0].run
if tokenRune != 'x' {
test.Fatalf (
"tokens does not reference the same memory as runes after changing runes: %c, %c",
runes[0].run, tokenRune)
}
runeIndex := 0
for tokenIndex, token := range tokens {
tokenRunePtr := &token.runes[0]
runePtr := &runes[runeIndex]
if runePtr != tokenRunePtr {
test.Fatalf (
"tokens[%d] does not reference runes[%d]: %p, %p",
tokenIndex, runeIndex, tokenRunePtr, runePtr)
}
runeIndex += len(token.runes)
}
2024-09-10 09:19:57 -06:00
}
func BenchmarkParseStringLatin (benchmark *testing.B) {
benchmark.ReportAllocs()
2024-09-19 07:33:14 -06:00
var rmeanLen, rmeanCap int
var tmeanLen, tmeanCap int
for i := 0; i < benchmark.N; i ++ {
2024-09-19 07:33:14 -06:00
runes, tokens := parseString(lipsumLt)
rmeanLen += len(runes)
rmeanCap += cap(runes)
tmeanLen += len(tokens)
tmeanCap += cap(tokens)
}
2024-09-19 07:33:14 -06:00
rmeanLen /= benchmark.N
rmeanCap /= benchmark.N
tmeanLen /= benchmark.N
tmeanCap /= benchmark.N
benchmark.ReportMetric(float64(rmeanCap) / float64(rmeanLen), "rune-waste")
benchmark.ReportMetric(float64(tmeanCap) / float64(tmeanLen), "token-waste")
}
func BenchmarkParseStringChinese (benchmark *testing.B) {
benchmark.ReportAllocs()
2024-09-19 07:33:14 -06:00
var rmeanLen, rmeanCap int
var tmeanLen, tmeanCap int
for i := 0; i < benchmark.N; i ++ {
2024-09-19 07:33:14 -06:00
runes, tokens := parseString(lipsumCn)
rmeanLen += len(runes)
rmeanCap += cap(runes)
tmeanLen += len(tokens)
tmeanCap += cap(tokens)
}
2024-09-19 07:33:14 -06:00
rmeanLen /= benchmark.N
rmeanCap /= benchmark.N
tmeanLen /= benchmark.N
tmeanCap /= benchmark.N
benchmark.ReportMetric(float64(rmeanCap) / float64(rmeanLen), "rune-waste")
benchmark.ReportMetric(float64(tmeanCap) / float64(tmeanLen), "token-waste")
}
const lipsumLt =
`Voluptatem impedit id id facilis et. Sit eligendi aspernatur dicta vitae ipsa officia enim harum. Occaecati quod harum quos temporibus officiis provident enim neque. Odio totam ducimus commodi quis minima ea.
Ut delectus quis a rem consectetur laudantium hic sequi. Vel sunt neque nisi excepturi id sit id ut. Dolores expedita et odio. Quibusdam sed et quam nostrum. Sed perspiciatis voluptatibus et.
Omnis qui tempore corrupti alias ut repellendus est. A officiis molestias perspiciatis ut dolores nihil. Ut officiis hic quo aut aut dolorum. Modi at molestiae praesentium ea eveniet aut porro.
Similique facere cum amet nesciunt dolorem nemo. Rerum temporibus iure maiores. Facere quam nihil quia debitis nihil est officia aliquam. Magnam aut alias consectetur. Velit cumque eligendi assumenda magni ratione. Est dolorem modi a unde.
Illo reprehenderit est sunt quaerat cum nihil non. Quia nihil placeat qui ex hic molestiae eligendi. Asperiores optio et nobis et.`
const lipsumCn =
`这很容易并且妨碍快乐让我们很难为这些人选择上述生活的职责他们被这样的事实蒙蔽了双眼他们现在不提供办公室我讨厌我们给小孩子们带来所有的好处
作为被选中的人他将跟随这里的赞美或者除非他们被排除在外否则他们不是意想不到的痛苦和仇恨但对某些人来说以及我们自己但让我们看看其中的乐趣和
当时所有腐败的人都必须被击退办公室的麻烦被视为无痛至于这里的服务无论是哪里还是让人心疼但目前的麻烦将会发生或持续下去
当没有人知道其中的痛苦时也要做同样的事情事物的时代确实更加伟大无所作为因为你不欠任何东西这是一些责任这将是伟大的或其他方面无论他选择什么他都必须非常小心有一种痛从何而来
他责怪他们在什么都没有的情况下才问因为没有人喜欢从这里选择麻烦对我们来说这是一个更艰难的选择
这很容易并且妨碍快乐让我们很难为这些人选择上述生活的职责他们被这样的事实蒙蔽了双眼他们现在不提供办公室我讨厌我们给小孩子们带来所有的好处
作为被选中的人他将跟随这里的赞美或者除非他们被排除在外否则他们不是意想不到的痛苦和仇恨但对某些人来说以及我们自己但让我们看看其中的乐趣和
当时所有腐败的人都必须被击退办公室的麻烦被视为无痛至于这里的服务无论是哪里还是让人心疼但目前的麻烦将会发生或持续下去
当没有人知道其中的痛苦时也要做同样的事情事物的时代确实更加伟大无所作为因为你不欠任何东西这是一些责任这将是伟大的或其他方面无论他选择什么他都必须非常小心有一种痛从何而来
他责怪他们在什么都没有的情况下才问因为没有人喜欢从这里选择麻烦对我们来说这是一个更艰难的选择
这很容易并且妨碍快乐让我们很难为这些人选择上述生活的职责他们被这样的事实蒙蔽了双眼他们现在不提供办公室我讨厌我们给小孩子们带来所有的好处
作为被选中的人他将跟随这里的赞美或者除非他们被排除在外否则他们不是意想不到的痛苦和仇恨但对某些人来说以及我们自己但让我们看看其中的乐趣和
当时所有腐败的人都必须被击退办公室的麻烦被视为无痛至于这里的服务无论是哪里还是让人心疼但目前的麻烦将会发生或持续下去
当没有人知道其中的痛苦时也要做同样的事情事物的`