package uniseg
import (
"testing"
)
type testCase = struct {
original string
expected [][]rune
}
// The test cases for the simple test function.
var testCases = []testCase{
{original: "", expected: [][]rune{}},
{original: "x", expected: [][]rune{{0x78}}},
{original: "basic", expected: [][]rune{{0x62}, {0x61}, {0x73}, {0x69}, {0x63}}},
{original: "möp", expected: [][]rune{{0x6d}, {0x6f, 0x308}, {0x70}}},
{original: "\r\n", expected: [][]rune{{0xd, 0xa}}},
{original: "\n\n", expected: [][]rune{{0xa}, {0xa}}},
{original: "\t*", expected: [][]rune{{0x9}, {0x2a}}},
{original: "뢴", expected: [][]rune{{0x1105, 0x116c, 0x11ab}}},
{original: "ܐܒܓܕ", expected: [][]rune{{0x710}, {0x70f, 0x712}, {0x713}, {0x715}}},
{original: "ำ", expected: [][]rune{{0xe33}}},
{original: "ำำ", expected: [][]rune{{0xe33, 0xe33}}},
{original: "สระอำ", expected: [][]rune{{0xe2a}, {0xe23}, {0xe30}, {0xe2d, 0xe33}}},
{original: "*뢴*", expected: [][]rune{{0x2a}, {0x1105, 0x116c, 0x11ab}, {0x2a}}},
{original: "*👩❤️💋👩*", expected: [][]rune{{0x2a}, {0x1f469, 0x200d, 0x2764, 0xfe0f, 0x200d, 0x1f48b, 0x200d, 0x1f469}, {0x2a}}},
{original: "👩❤️💋👩", expected: [][]rune{{0x1f469, 0x200d, 0x2764, 0xfe0f, 0x200d, 0x1f48b, 0x200d, 0x1f469}}},
{original: "🏋🏽♀️", expected: [][]rune{{0x1f3cb, 0x1f3fd, 0x200d, 0x2640, 0xfe0f}}},
{original: "🙂", expected: [][]rune{{0x1f642}}},
{original: "🙂🙂", expected: [][]rune{{0x1f642}, {0x1f642}}},
{original: "🇩🇪", expected: [][]rune{{0x1f1e9, 0x1f1ea}}},
{original: "🏳️🌈", expected: [][]rune{{0x1f3f3, 0xfe0f, 0x200d, 0x1f308}}},
{original: "\t🏳️🌈", expected: [][]rune{{0x9}, {0x1f3f3, 0xfe0f, 0x200d, 0x1f308}}},
{original: "\t🏳️🌈\t", expected: [][]rune{{0x9}, {0x1f3f3, 0xfe0f, 0x200d, 0x1f308}, {0x9}}},
}
// decomposed returns a grapheme cluster decomposition.
func decomposed(s string) (runes [][]rune) {
gr := NewGraphemes(s)
for gr.Next() {
runes = append(runes, gr.Runes())
}
return
}
// Run the testCases slice above.
func TestSimple(t *testing.T) {
allCases := append(testCases, unicodeTestCases...)
for testNum, testCase := range allCases {
/*t.Logf(`Test case %d "%s": Expecting %x, getting %x, code points %x"`,
testNum,
strings.TrimSpace(testCase.original),
testCase.expected,
decomposed(testCase.original),
[]rune(testCase.original))*/
gr := NewGraphemes(testCase.original)
var index int
GraphemeLoop:
for index = 0; gr.Next(); index++ {
if index >= len(testCase.expected) {
t.Errorf(`Test case %d "%s" failed: More grapheme clusters returned than expected %d`,
testNum,
testCase.original,
len(testCase.expected))
break
}
cluster := gr.Runes()
if len(cluster) != len(testCase.expected[index]) {
t.Errorf(`Test case %d "%s" failed: Grapheme cluster at index %d has %d codepoints %x, %d expected %x`,
testNum,
testCase.original,
index,
len(cluster),
cluster,
len(testCase.expected[index]),
testCase.expected[index])
break
}
for i, r := range cluster {
if r != testCase.expected[index][i] {
t.Errorf(`Test case %d "%s" failed: Grapheme cluster at index %d is %x, expected %x`,
testNum,
testCase.original,
index,
cluster,
testCase.expected[index])
break GraphemeLoop
}
}
}
if index < len(testCase.expected) {
t.Errorf(`Test case %d "%s" failed: Fewer grapheme clusters returned (%d) than expected (%d)`,
testNum,
testCase.original,
index,
len(testCase.expected))
}
}
}
// Test the Str() function.
func TestStr(t *testing.T) {
gr := NewGraphemes("möp")
gr.Next()
gr.Next()
gr.Next()
if str := gr.Str(); str != "p" {
t.Errorf(`Expected "p", got "%s"`, str)
}
}
// Test the Bytes() function.
func TestBytes(t *testing.T) {
gr := NewGraphemes("A👩❤️💋👩B")
gr.Next()
gr.Next()
gr.Next()
b := gr.Bytes()
if len(b) != 1 {
t.Fatalf(`Expected len("B") == 1, got %d`, len(b))
}
if b[0] != 'B' {
t.Errorf(`Expected "B", got "%s"`, string(b[0]))
}
}
// Test the Positions() function.
func TestPositions(t *testing.T) {
gr := NewGraphemes("A👩❤️💋👩B")
gr.Next()
gr.Next()
from, to := gr.Positions()
if from != 1 || to != 28 {
t.Errorf(`Expected from=%d to=%d, got from=%d to=%d`, 1, 28, from, to)
}
}
// Test the Reset() function.
func TestReset(t *testing.T) {
gr := NewGraphemes("möp")
gr.Next()
gr.Next()
gr.Next()
gr.Reset()
gr.Next()
if str := gr.Str(); str != "m" {
t.Errorf(`Expected "m", got "%s"`, str)
}
}
// Test retrieving clusters before calling Next().
func TestEarly(t *testing.T) {
gr := NewGraphemes("test")
r := gr.Runes()
if r != nil {
t.Errorf(`Expected nil rune slice, got %x`, r)
}
str := gr.Str()
if str != "" {
t.Errorf(`Expected empty string, got "%s"`, str)
}
b := gr.Bytes()
if b != nil {
t.Errorf(`Expected byte rune slice, got %x`, b)
}
from, to := gr.Positions()
if from != 0 || to != 0 {
t.Errorf(`Expected from=%d to=%d, got from=%d to=%d`, 0, 0, from, to)
}
}
// Test retrieving more clusters after retrieving the last cluster.
func TestLate(t *testing.T) {
gr := NewGraphemes("x")
gr.Next()
gr.Next()
r := gr.Runes()
if r != nil {
t.Errorf(`Expected nil rune slice, got %x`, r)
}
str := gr.Str()
if str != "" {
t.Errorf(`Expected empty string, got "%s"`, str)
}
b := gr.Bytes()
if b != nil {
t.Errorf(`Expected byte rune slice, got %x`, b)
}
from, to := gr.Positions()
if from != 1 || to != 1 {
t.Errorf(`Expected from=%d to=%d, got from=%d to=%d`, 1, 1, from, to)
}
}
// Test the GraphemeClusterCount function.
func TestCount(t *testing.T) {
if n := GraphemeClusterCount("🇩🇪🏳️🌈"); n != 2 {
t.Errorf(`Expected 2 grapheme clusters, got %d`, n)
}
}