package bidi import ( "log" "testing" ) type runInformation struct { str string dir Direction start int end int } func TestSimple(t *testing.T) { str := "Hellö" p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } expectedRuns := []runInformation{ {"Hellö", LeftToRight, 0, 4}, } if !p.IsLeftToRight() { t.Error("p.IsLeftToRight() == false; want true") } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start %d, end %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestMixed(t *testing.T) { str := `العاشر ليونيكود (Unicode Conference)، الذي سيعقد في 10-12 آذار 1997 مبدينة` p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } if p.IsLeftToRight() { t.Error("p.IsLeftToRight() == true; want false") } expectedRuns := []runInformation{ {"العاشر ليونيكود (", RightToLeft, 0, 16}, {"Unicode Conference", LeftToRight, 17, 34}, {")، الذي سيعقد في ", RightToLeft, 35, 51}, {"10", LeftToRight, 52, 53}, {"-", RightToLeft, 54, 54}, {"12", LeftToRight, 55, 56}, {" آذار ", RightToLeft, 57, 62}, {"1997", LeftToRight, 63, 66}, {" مبدينة", RightToLeft, 67, 73}, } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start = %d, end = %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestExplicitIsolate(t *testing.T) { // https://www.w3.org/International/articles/inline-bidi-markup/uba-basics.en#beyond str := "The names of these states in Arabic are \u2067مصر\u2069, \u2067البحرين\u2069 and \u2067الكويت\u2069 respectively." p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } if !p.IsLeftToRight() { t.Error("p.IsLeftToRight() == false; want true") } expectedRuns := []runInformation{ {"The names of these states in Arabic are \u2067", LeftToRight, 0, 40}, {"مصر", RightToLeft, 41, 43}, {"\u2069, \u2067", LeftToRight, 44, 47}, {"البحرين", RightToLeft, 48, 54}, {"\u2069 and \u2067", LeftToRight, 55, 61}, {"الكويت", RightToLeft, 62, 67}, {"\u2069 respectively.", LeftToRight, 68, 82}, } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start = %d, end = %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestWithoutExplicitIsolate(t *testing.T) { str := "The names of these states in Arabic are مصر, البحرين and الكويت respectively." p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } if !p.IsLeftToRight() { t.Error("p.IsLeftToRight() == false; want true") } expectedRuns := []runInformation{ {"The names of these states in Arabic are ", LeftToRight, 0, 39}, {"مصر, البحرين", RightToLeft, 40, 51}, {" and ", LeftToRight, 52, 56}, {"الكويت", RightToLeft, 57, 62}, {" respectively.", LeftToRight, 63, 76}, } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start = %d, end = %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestLongUTF8(t *testing.T) { str := `𠀀` p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } if !p.IsLeftToRight() { t.Error("p.IsLeftToRight() == false; want true") } expectedRuns := []runInformation{ {"𠀀", LeftToRight, 0, 0}, } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start = %d, end = %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestLLongUTF8(t *testing.T) { strTester := []struct { str string l int }{ {"ö", 2}, {"ॡ", 3}, {`𠀀`, 4}, } for _, st := range strTester { str := st.str want := st.l if _, l := LookupString(str); l != want { t.Errorf("LookupString(%q) length = %d; want %d", str, l, want) } } } func TestMixedSimple(t *testing.T) { str := `Uا` p := Paragraph{} p.SetString(str) order, err := p.Order() if err != nil { log.Fatal(err) } if !p.IsLeftToRight() { t.Error("p.IsLeftToRight() == false; want true") } expectedRuns := []runInformation{ {"U", LeftToRight, 0, 0}, {"ا", RightToLeft, 1, 1}, } if nr, want := order.NumRuns(), len(expectedRuns); nr != want { t.Errorf("order.NumRuns() = %d; want %d", nr, want) } for i, want := range expectedRuns { r := order.Run(i) if got := r.String(); got != want.str { t.Errorf("Run(%d) = %q; want %q", i, got, want.str) } if s, e := r.Pos(); s != want.start || e != want.end { t.Errorf("Run(%d).start = %d, .end = %d; want start = %d, end = %d", i, s, e, want.start, want.end) } if d := r.Direction(); d != want.dir { t.Errorf("Run(%d).Direction = %d; want %d", i, d, want.dir) } } } func TestDefaultDirection(t *testing.T) { str := "+" p := Paragraph{} p.SetString(str, DefaultDirection(RightToLeft)) _, err := p.Order() if err != nil { t.Error(err) t.Fail() } if want, dir := false, p.IsLeftToRight(); want != dir { t.Errorf("p.IsLeftToRight() = %t; want %t", dir, want) } p.SetString(str, DefaultDirection(LeftToRight)) _, err = p.Order() if err != nil { t.Error(err) t.Fail() } if want, dir := true, p.IsLeftToRight(); want != dir { t.Errorf("p.IsLeftToRight() = %t; want %t", dir, want) } } func TestEmpty(t *testing.T) { p := Paragraph{} p.SetBytes([]byte{}) o, err := p.Order() if err != nil { t.Error("p.Order() return err != nil; want err == nil") } if nr := o.NumRuns(); nr != 0 { t.Errorf("o.NumRuns() = %d; want 0", nr) } } func TestNewline(t *testing.T) { str := "Hello\nworld" p := Paragraph{} n, err := p.SetString(str) if err != nil { t.Error(err) } // 6 is the length up to and including the \n if want := 6; n != want { t.Errorf("SetString(%q) = nil, %d; want nil, %d", str, n, want) } } func TestDoubleSetString(t *testing.T) { str := "العاشر ليونيكود (Unicode Conference)،" p := Paragraph{} _, err := p.SetString(str) if err != nil { t.Error(err) } _, err = p.SetString(str) if err != nil { t.Error(err) } _, err = p.Order() if err != nil { t.Error(err) } } func TestReverseString(t *testing.T) { input := "(Hello)" want := "(olleH)" if str := ReverseString(input); str != want { t.Errorf("ReverseString(%s) = %q; want %q", input, str, want) } } func TestAppendReverse(t *testing.T) { testcase := []struct { inString string outString string want string }{ {"", "Hëllo", "Hëllo"}, {"nice (wörld)", "", "(dlröw) ecin"}, {"nice (wörld)", "Hëllo", "Hëllo(dlröw) ecin"}, } for _, tc := range testcase { if r := AppendReverse([]byte(tc.outString), []byte(tc.inString)); string(r) != tc.want { t.Errorf("AppendReverse([]byte(%q), []byte(%q) = %q; want %q", tc.outString, tc.inString, string(r), tc.want) } } }