func TestNewRichText_EnglishRussianAndChineseLanguages(t *testing.T) { st := SuperTest{t} afmFonts := afm_fonts.Families("Helvetica") ttfFonts := ttf_fonts.Families("Arial", "STFangsong") fonts := append(afmFonts, ttfFonts...) rt, err := New(englishRussianChinese, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } st.Must(len(rt.pieces) == 5) st.Equal("Here is some Russian, ", rt.pieces[0].Text) st.Equal(10.0, rt.pieces[0].FontSize) st.Equal("Неприкосновенность", rt.pieces[1].Text) st.Equal(10.0, rt.pieces[1].FontSize) st.Equal(", and some Chinese, ", rt.pieces[2].Text) st.Equal(10.0, rt.pieces[2].FontSize) st.Equal("表明你已明确同意你的回答接受评估", rt.pieces[3].Text) st.Equal(10.0, rt.pieces[3].FontSize) st.Equal(".", rt.pieces[4].Text) st.Equal(10.0, rt.pieces[4].FontSize) st.Equal(fonts[0], rt.pieces[0].Font, "Should be tagged with Helvetica font.") st.Equal(fonts[1], rt.pieces[1].Font, "Should be tagged with Arial font.") st.Equal(fonts[0], rt.pieces[2].Font, "Should be tagged with Helvetica font.") st.Equal(fonts[2], rt.pieces[3].Font, "Should be tagged with STFangsong font.") st.Equal(fonts[0], rt.pieces[4].Font, "Should be tagged with Helvetica font.") }
func TestRichText_IsNewLine(t *testing.T) { st := SuperTest{t} font := ttf_fonts.Families("Arial")[0] empty := RichText{ Text: "", Font: font, FontSize: 10, } st.False(empty.IsNewLine(), "An empty string is not a newline.") newline := RichText{ Text: "\n", Font: font, FontSize: 10, } st.True(newline.IsNewLine(), "It really is a newline.") nonNewline := RichText{ Text: "Lorem", Font: font, FontSize: 10, } st.False(nonNewline.IsNewLine(), "This isn't a newline.") }
func arialText(s string) *RichText { rt, err := New(s, ttf_fonts.Families("Arial"), 10, options.Options{}) if err != nil { panic(err) } return rt }
func TestNewRichText_EnglishAndChinese_Pass(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("Arial", "STFangsong") rt, err := New("abc所有测def", fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } st.Equal(3, len(rt.pieces)) st.Equal("abc", rt.pieces[0].Text) st.Equal(10.0, rt.pieces[0].FontSize) st.Equal(colors.Black, rt.pieces[0].Color, "Color should be (default) black.") st.False(rt.pieces[0].Underline, "Underline should be (default) false.") st.False(rt.pieces[0].LineThrough, "LineThrough should be (default) false.") st.Equal("所有测", rt.pieces[1].Text) st.Equal(10.0, rt.pieces[1].FontSize) st.Equal(colors.Black, rt.pieces[1].Color, "Color should be (default) black.") st.False(rt.pieces[1].Underline, "Underline should be (default) false.") st.False(rt.pieces[1].LineThrough, "LineThrough should be (default) false.") st.Equal("def", rt.pieces[2].Text) st.Equal(10.0, rt.pieces[2].FontSize) st.Equal(colors.Black, rt.pieces[2].Color, "Color should be (default) black.") st.False(rt.pieces[2].Underline, "Underline should be (default) false.") st.False(rt.pieces[2].LineThrough, "LineThrough should be (default) false.") st.Equal(fonts[0], rt.pieces[0].Font, "abc should be tagged with Arial font.") st.Equal(fonts[1], rt.pieces[1].Font, "Chinese should be tagged with STFangsong font.") st.Equal(fonts[0], rt.pieces[2].Font, "def should be tagged with Arial font.") }
func richTextMixedText() *RichText { rt, err := New("abc所有测def", ttf_fonts.Families("Arial", "STFangsong"), 10, options.Options{}) if err != nil { panic(err) } return rt }
func TestRichText_InsertStringAtOffsets(t *testing.T) { st := SuperTest{t} afmFonts := afm_fonts.Families("Helvetica") ttfFonts := ttf_fonts.Families("Arial", "STFangsong") fonts := append(afmFonts, ttfFonts...) text := "Automatic " text1 := "hyphenation " text2 := "aids word wrapping." rt, err := New(text, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } rt, err = rt.Add(text1, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } rt, err = rt.Add(text2, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } offsets := []int{4, 16, 36} chars := rt.Chars() rt0 := rt.InsertStringAtOffsets("-", offsets) st.Equal("Auto-matic hyphen-ation aids word wrap-ping.", rt0.String()) st.Equal(chars+len(offsets), rt0.Chars(), "New text should be larger.") }
func courierNewText(s string) *RichText { rt, err := New(s, ttf_fonts.Families("Courier New"), 10, options.Options{}) if err != nil { panic(err) } return rt }
func TestNewRichText_EnglishAndChinese_substitute(t *testing.T) { st := SuperTest{t} rt, err := New("abc所有测", ttf_fonts.Families("Arial"), 10, options.Options{}) if err != nil { t.Fatal(err) } st.Equal("abc???", rt.String()) }
func mixedText() *RichText { afmFonts := afm_fonts.Families("Helvetica") ttfFonts := ttf_fonts.Families("Arial", "STFangsong") fonts := append(afmFonts, ttfFonts...) rt, err := New(englishRussianChinese, fonts, 10, options.Options{}) if err != nil { panic(err) } return rt }
// With Chinese font first in list, Arial is not called upon for English. func TestNewRichText_ChineseAndEnglish_Reversed(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("STFangsong", "Arial") rt, err := New("所有测abc", fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } st.Must(len(rt.pieces) == 0) st.Equal("所有测abc", rt.Text) st.Equal(10.0, rt.FontSize) st.Equal(fonts[0], rt.Font, "Should be tagged with Arial font.") }
func TestRichText_WrapToWidth_short(t *testing.T) { st := SuperTest{t} p, err := New("Lorem ipsum.", ttf_fonts.Families("Arial"), 10, options.Options{"nobreak": true}) if err != nil { t.Fatal(err) } flags := make([]wordbreaking.Flags, p.Len()) wordbreaking.MarkRuneAttributes(p.String(), flags) lines := p.WrapToWidth(100, flags, false) st.Must(len(lines) == 1, "Should return one line.") st.Equal(p.Text, lines[0].Text, "Text should match.") st.True(p.MatchesAttributes(lines[0])) }
func TestRichText_MatchesAttributes(t *testing.T) { st := SuperTest{t} font := ttf_fonts.Families("Arial")[0] p1 := RichText{ Text: "Lorem", Font: font, FontSize: 10, } p2 := p1 st.True(p1.MatchesAttributes(&p2), "Attributes should match.") p2.Font = ttf_fonts.Families("Arial")[0] st.True(p1.MatchesAttributes(&p2), "Attributes should match.") p2.FontSize = 12 st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") p2 = p1 p2.Color = colors.Azure st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") p2 = p1 p2.Underline = true st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") p2 = p1 p2.LineThrough = true st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") p2 = p1 p2.CharSpacing = 1 st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") p2 = p1 p2.WordSpacing = 1 st.False(p1.MatchesAttributes(&p2), "Attributes should not match.") }
// 14,930 ns go1.1.2 // 14,685 ns go1.2.1 // 10,873 ns go1.4.2 // 5,664 ns go1.7.3 mbp func BenchmarkNewRichText(b *testing.B) { b.StopTimer() afmFonts := afm_fonts.Families("Helvetica") ttfFonts := ttf_fonts.Families("Arial", "STFangsong") fonts := append(afmFonts, ttfFonts...) b.StartTimer() for i := 0; i < b.N; i++ { _, err := New(englishRussianChinese, fonts, 10, options.Options{}) if err != nil { b.Fatal(err) } } }
// 75.5 ns // 76.9 ns go1.1.1 // 70.8 ns go1.1.2 // 74.1 ns go1.2.1 // 77.8 ns go1.4.2 // 48.3 ns go1.7.3 mbp func BenchmarkRichText_IsWhiteSpace(b *testing.B) { b.StopTimer() font := ttf_fonts.Families("Arial")[0] piece := &RichText{ Text: " \t\n\v\f\r", Font: font, FontSize: 10, } b.StartTimer() for i := 0; i < b.N; i++ { piece.IsWhiteSpace() } }
func TestRichText_WrapToWidth_nobreak_simple(t *testing.T) { st := SuperTest{t} rt, err := New( "Here is a long sentence with mostly small words.", ttf_fonts.Families("Arial"), 10, options.Options{"nobreak": true}) if err != nil { t.Fatal(err) } flags := make([]wordbreaking.Flags, rt.Len()) wordbreaking.MarkRuneAttributes(rt.String(), flags) rt.MarkNoBreak(flags) lines := rt.WrapToWidth(60, flags, false) st.Equal(1, len(lines), "Should return a single line.") }
func TestRichText_TrimRightFunc_complex(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("Arial") t1, err := New(whiteSpaceText_complex1, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } t2, err2 := t1.Add(whiteSpaceText_complex2, fonts, 10, options.Options{}) if err2 != nil { t.Fatal(err2) } st.Equal(trailingwhiteSpaceText_simple, t2.String()) t3 := t2.TrimRightFunc(unicode.IsSpace) st.Equal(trailingwhiteSpaceText_simple_trimmed, t3.String()) }
func TestNewRichText_English(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("Arial") rt, err := New("abc", fonts, 10, options.Options{"color": colors.Green, "underline": true, "line_through": true, "nobreak": true}) if err != nil { t.Fatal(err) } st.Equal("abc", rt.Text) st.Equal(10.0, rt.FontSize) st.Equal(colors.Green, rt.Color) st.True(rt.Underline) st.True(rt.LineThrough) st.True(rt.NoBreak) st.Equal(fonts[0], rt.Font, "Should be tagged with Arial font.") }
func TestRichText_Height(t *testing.T) { st := SuperTest{t} p := new(RichText) st.Equal(0.0, p.Height()) fonts := ttf_fonts.Families("Courier New", "STFangsong") p, err := New("abc所有测", fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } ascent0 := p.pieces[0].Ascent() descent0 := p.pieces[0].Descent() ascent1 := p.pieces[1].Ascent() descent1 := p.pieces[1].Descent() maxAscent := math.Max(ascent0, ascent1) minDecent := math.Min(descent0, descent1) expected := maxAscent + -minDecent st.AlmostEqual(expected, p.Height(), 0.001, "Where baselines do not match, Height should allow for the tallest Ascent and Descent.") st.AlmostEqual(11.6029296875, p.Height(), 0.001) }
func TestRichText_Merge_width_chars(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("Arial") text := "Here is some " text1 := "English text." original, err := New(text, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } original, err = original.Add(text1, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } width0 := original.Width() chars0 := original.Chars() merged := original.Merge() st.Equal(width0, merged.Width(), "Merged text should be the same width as before.") st.Equal(chars0, merged.Chars(), "Merged text should have same char count as before.") }
func TestRichText_IsWhiteSpace(t *testing.T) { st := SuperTest{t} font := ttf_fonts.Families("Arial")[0] empty := RichText{ Text: "", Font: font, FontSize: 10, } st.False(empty.IsWhiteSpace(), "Empty string should not be considered whitespace.") singleWhite := RichText{ Text: " ", Font: font, FontSize: 10, } st.True(singleWhite.IsWhiteSpace(), "A single space should be considered whitespace.") multiWhite := RichText{ Text: " \t\n\v\f\r", Font: font, FontSize: 10, } st.True(multiWhite.IsWhiteSpace(), "Multiple spaces should be considered whitespace.") startWhite := RichText{ Text: " Lorem", Font: font, FontSize: 10, } st.False(startWhite.IsWhiteSpace(), "A piece that only starts with spaces should not be considered whitespace.") nonWhite := RichText{ Text: "Lorem", Font: font, FontSize: 10, } st.False(nonWhite.IsWhiteSpace(), "Piece contains no whitespace.") }
func TestRichText_WrapToWidth_nobreak_complex(t *testing.T) { st := SuperTest{t} fonts := ttf_fonts.Families("Arial") var rt *RichText var err error rt, err = New("Here is a ", fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } rt, err = rt.Add("long sentence with mostly", fonts, 10, options.Options{"nobreak": true}) if err != nil { t.Fatal(err) } rt, err = rt.Add(" small words.", fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } flags := make([]wordbreaking.Flags, rt.Len()) wordbreaking.MarkRuneAttributes(rt.String(), flags) rt.MarkNoBreak(flags) lines := rt.WrapToWidth(60, flags, false) st.Equal(3, len(lines), "Should return 3 lines.") }
func TestRichText_Merge(t *testing.T) { st := SuperTest{t} afmFonts := afm_fonts.Families("Helvetica") ttfFonts := ttf_fonts.Families("Arial", "STFangsong") fonts := append(afmFonts, ttfFonts...) text := "Here is some " text1 := "Russian, Неприкосновенность, " text2 := "and some Chinese, 表明你已明确同意你的回答接受评估." original, err := New(text, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } original, err = original.Add(text1, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } original, err = original.Add(text2, fonts, 10, options.Options{}) if err != nil { t.Fatal(err) } // fmt.Println("Original pieces: ", original.Count()) // i := 0 // original.VisitAll(func(p *RichText) { // i++ // fmt.Println(i, p.Text, len(p.Pieces)) // }) // Node // Leaf: Here is some 0 // Node // Leaf: Russian, // Leaf: Неприкосновенность // Leaf: , // Node // Leaf: and some Chinese, // Leaf: 表明你已明确同意你的回答接受评估 // Leaf: . piece0 := *original.pieces[0] merged := original.Merge() // fmt.Println("Merged pieces: ", merged.Count()) // i = 0 // merged.VisitAll(func(p *RichText) { // i++ // fmt.Println(i, p.Text, len(p.pieces)) // }) // Node // Leaf: Here is some Russian, // Leaf: Неприкосновенность // Leaf: , and some Chinese, // Leaf: 表明你已明确同意你的回答接受评估 // Leaf: . st.Equal(text+text1+text2, merged.String()) st.Must(len(merged.pieces) == 5) st.Equal("Here is some Russian, ", merged.pieces[0].Text) st.Equal(10.0, merged.pieces[0].FontSize) st.Equal(fonts[0], merged.pieces[0].Font, "Should be tagged with Helvetica font.") st.Equal("Неприкосновенность", merged.pieces[1].Text) st.Equal(10.0, merged.pieces[1].FontSize) st.Equal(fonts[1], merged.pieces[1].Font, "Should be tagged with Arial font.") st.Equal(", and some Chinese, ", merged.pieces[2].Text) st.Equal(10.0, merged.pieces[2].FontSize) st.Equal(fonts[0], merged.pieces[2].Font, "Should be tagged with Helvetica font.") st.Equal("表明你已明确同意你的回答接受评估", merged.pieces[3].Text) st.Equal(10.0, merged.pieces[3].FontSize) st.Equal(fonts[2], merged.pieces[3].Font, "Should be tagged with STFangsong font.") st.Equal(".", merged.pieces[4].Text) st.Equal(10.0, merged.pieces[4].FontSize) st.Equal(fonts[0], merged.pieces[4].Font, "Should be tagged with Helvetica font.") st.Equal(piece0.Text, original.pieces[0].Text, "Original should be unchanged.") }
func TestNewRichText_EnglishAndChinese_Fail(t *testing.T) { st := SuperTest{t} _, err := New("abc所有测", ttf_fonts.Families("Arial", ""), 10, options.Options{}) st.False(err == nil, "New should fail with Chinese text and only Arial.") st.Equal("No font found for 所有测.", err.Error()) }