// TestAlloc tests that some mapping methods should not cause any allocation. func TestAlloc(t *testing.T) { dst := make([]byte, 256) // big enough to hold any result src := []byte(txtNonASCII) for i, f := range []func() Caser{ func() Caser { return Upper(language.Und) }, func() Caser { return Lower(language.Und) }, func() Caser { return Title(language.Und) }, } { var c Caser v := testtext.AllocsPerRun(2, func() { c = f() }) if v > 1 { // TODO: Right now only Upper has 1 allocation. Special-case Lower // and Title as well to have less allocations for the root locale. t.Skipf("%d:init: number of allocs was %f; want 0", i, v) } v = testtext.AllocsPerRun(2, func() { c.Transform(dst, src, true) }) if v > 0 { t.Errorf("%d:transform: number of allocs was %f; want 0", i, v) } } }
// TestAlloc tests that some mapping methods should not cause any allocation. func TestAlloc(t *testing.T) { dst := make([]byte, 256) // big enough to hold any result src := []byte(txtNonASCII) for i, f := range []func() Caser{ func() Caser { return Upper(language.Und) }, func() Caser { return Lower(language.Und) }, func() Caser { return Lower(language.Und, HandleFinalSigma(false)) }, // TODO: use a shared copy for these casers as well, in order of // importance, starting with the most important: // func() Caser { return Title(language.Und) }, // func() Caser { return Title(language.Und, HandleFinalSigma(false)) }, } { testtext.Run(t, "", func(t *testing.T) { var c Caser v := testtext.AllocsPerRun(10, func() { c = f() }) if v > 0 { // TODO: Right now only Upper has 1 allocation. Special-case Lower // and Title as well to have less allocations for the root locale. t.Errorf("%d:init: number of allocs was %f; want 0", i, v) } v = testtext.AllocsPerRun(2, func() { c.Transform(dst, src, true) }) if v > 0 { t.Errorf("%d:transform: number of allocs was %f; want 0", i, v) } }) } }
func TestNumericWeighterAlloc(t *testing.T) { buf := make([]Elem, 100) w := NewNumericWeighter(numWeighter) s := "1234567890a" nNormal := testtext.AllocsPerRun(3, func() { numWeighter.AppendNextString(buf, s) }) nNumeric := testtext.AllocsPerRun(3, func() { w.AppendNextString(buf, s) }) if n := nNumeric - nNormal; n > 0 { t.Errorf("got %f; want 0", n) } }
func TestReplaceIllFormedAlloc(t *testing.T) { if n := testtext.AllocsPerRun(3, func() { ReplaceIllFormed().Transform(nil, nil, false) }); n > 0 { t.Errorf("got %f; want 0", n) } }
func TestRemoveAlloc(t *testing.T) { if n := testtext.AllocsPerRun(3, func() { Remove(Predicate(rmNop)).Transform(nil, nil, false) }); n > 0 { t.Errorf("got %f; want 0", n) } }
func TestMapAlloc(t *testing.T) { if n := testtext.AllocsPerRun(3, func() { Map(idem).Transform(nil, nil, false) }); n > 0 { t.Errorf("got %f; want 0", n) } }
func TestFold(t *testing.T) { for _, tc := range foldTestCases { testEntry := func(name string, c Caser, m func(r rune) string) { want := "" for _, r := range tc { want += m(r) } if got := c.String(tc); got != want { t.Errorf("%s(%s) = %+q; want %+q", name, tc, got, want) } dst := make([]byte, 256) // big enough to hold any result src := []byte(tc) v := testtext.AllocsPerRun(20, func() { c.Transform(dst, src, true) }) if v > 0 { t.Errorf("%s(%s): number of allocs was %f; want 0", name, tc, v) } } testEntry("FullFold", Fold(), func(r rune) string { return runeFoldData(r).full }) // TODO: // testEntry("SimpleFold", Fold(Compact), func(r rune) string { // return runeFoldData(r).simple // }) // testEntry("SpecialFold", Fold(Turkic), func(r rune) string { // return runeFoldData(r).special // }) } }
func TestAppendMallocs(t *testing.T) { str := []byte("helloworld") out := make([]byte, 0, len(str)) if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.Append(out, str) }); n > 0 { t.Errorf("got %f allocs, want 0", n) } }
func TestMakeString(t *testing.T) { tests := []struct{ in, out string }{ {"und", "und"}, {"und", "und-CW"}, {"nl", "nl-NL"}, {"de-1901", "nl-1901"}, {"de-1901", "de-Arab-1901"}, {"x-a-b", "de-Arab-x-a-b"}, {"x-a-b", "x-a-b"}, } for i, tt := range tests { id, _ := Parse(tt.in) mod, _ := Parse(tt.out) id.setTagsFrom(mod) for j := 0; j < 2; j++ { id.remakeString() if str := id.String(); str != tt.out { t.Errorf("%d:%d: found %s; want %s", i, j, id.String(), tt.out) } } // The bytes to string conversion as used in remakeString // occasionally measures as more than one alloc, breaking this test. // To alleviate this we set the number of runs to more than 1. if n := testtext.AllocsPerRun(8, id.remakeString); n > 1 { t.Errorf("%d: # allocs got %.1f; want <= 1", i, n) } } }
func TestAllocToASCII(t *testing.T) { avg := testtext.AllocsPerRun(1000, func() { ToASCII("www.golang.org") }) if avg > 0 { t.Errorf("got %f; want 0", avg) } }
func TestBestMatchAlloc(t *testing.T) { m := NewMatcher(parseSupported("en sr nl")) // Go allocates when creating a list of tags from a single tag! list := []Tag{English} avg := testtext.AllocsPerRun(1, func() { m.Match(list...) }) if avg > 0 { t.Errorf("got %f; want 0", avg) } }
func TestTransformMallocs(t *testing.T) { str := []byte("helloworld") out := make([]byte, 0, len(str)) tr := UsernameCaseMapped.NewTransformer() if n := testtext.AllocsPerRun(100, func() { tr.Reset() tr.Transform(out, str, true) }); n > 0 { t.Errorf("got %f allocs, want 0", n) } }
func TestFold(t *testing.T) { testCases := []string{ "βß\u13f8", // "βssᏰ" "ab\u13fc\uab7aꭰ", // abᏴᎪᎠ "affifflast", // affifflast "Iİiı\u0345", // ii̇iıι "µµΜΜςσΣΣ", // μμμμσσσσ } for _, tc := range testCases { testEntry := func(name string, c Caser, m func(r rune) string) { want := "" for _, r := range tc { want += m(r) } if got := c.String(tc); got != want { t.Errorf("%s(%s) = %+q; want %+q", name, tc, got, want) } dst := make([]byte, 256) // big enough to hold any result src := []byte(tc) v := testtext.AllocsPerRun(20, func() { c.Transform(dst, src, true) }) if v > 0 { t.Errorf("%s(%s): number of allocs was %f; want 0", name, tc, v) } } testEntry("FullFold", Fold(), func(r rune) string { return runeFoldData(r).full }) // TODO: // testEntry("SimpleFold", Fold(Compact), func(r rune) string { // return runeFoldData(r).simple // }) // testEntry("SpecialFold", Fold(Turkic), func(r rune) string { // return runeFoldData(r).special // }) } }
func TestCaseMappings(t *testing.T) { for i, tt := range testCases { src, ok := tt.src.([]string) if !ok { src = strings.Split(tt.src.(string), " ") } for _, lang := range strings.Split(tt.lang, " ") { tag := language.MustParse(lang) testEntry := func(name string, mk func(language.Tag, options) transform.Transformer, gold interface{}) { c := Caser{mk(tag, tt.opts)} if gold != nil { wants, ok := gold.([]string) if !ok { wants = strings.Split(gold.(string), " ") } for j, want := range wants { if got := c.String(src[j]); got != want { t.Errorf("%d:%s:\n%s.String(%+q):\ngot %+q;\nwant %+q", i, lang, name, src[j], got, want) } } } dst := make([]byte, 256) // big enough to hold any result src := []byte(strings.Join(src, " ")) v := testtext.AllocsPerRun(20, func() { c.Transform(dst, src, true) }) if v > 1.1 { t.Errorf("%d:%s:\n%s: number of allocs was %f; want 0", i, lang, name, v) } } testEntry("Upper", makeUpper, tt.upper) testEntry("Lower", makeLower, tt.lower) testEntry("Title", makeTitle, tt.title) } } }
func TestStringMallocs(t *testing.T) { if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.String("helloworld") }); n > 0 { // TODO: reduce this to 0. t.Skipf("got %f allocs, want 0", n) } }
func TestString(t *testing.T) { testtext.Run(t, "transform", func(t *testing.T) { testString(t, String) }) // Overrun the internal destination buffer. for i, s := range []string{ aaa[:1*initialBufSize-1], aaa[:1*initialBufSize+0], aaa[:1*initialBufSize+1], AAA[:1*initialBufSize-1], AAA[:1*initialBufSize+0], AAA[:1*initialBufSize+1], AAA[:2*initialBufSize-1], AAA[:2*initialBufSize+0], AAA[:2*initialBufSize+1], aaa[:1*initialBufSize-2] + "A", aaa[:1*initialBufSize-1] + "A", aaa[:1*initialBufSize+0] + "A", aaa[:1*initialBufSize+1] + "A", } { testtext.Run(t, fmt.Sprint("dst buffer test using lower/", i), func(t *testing.T) { got, _, _ := String(lowerCaseASCII{}, s) if want := strings.ToLower(s); got != want { t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want)) } }) } // Overrun the internal source buffer. for i, s := range []string{ aaa[:1*initialBufSize-1], aaa[:1*initialBufSize+0], aaa[:1*initialBufSize+1], aaa[:2*initialBufSize+1], aaa[:2*initialBufSize+0], aaa[:2*initialBufSize+1], } { testtext.Run(t, fmt.Sprint("src buffer test using rleEncode/", i), func(t *testing.T) { got, _, _ := String(rleEncode{}, s) if want := fmt.Sprintf("%da", len(s)); got != want { t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want)) } }) } // Test allocations for non-changing strings. // Note we still need to allocate a single buffer. for i, s := range []string{ "", "123456789", aaa[:initialBufSize-1], aaa[:initialBufSize+0], aaa[:initialBufSize+1], aaa[:10*initialBufSize], } { testtext.Run(t, fmt.Sprint("alloc/", i), func(t *testing.T) { if n := testtext.AllocsPerRun(5, func() { String(&lowerCaseASCIILookahead{}, s) }); n > 1 { t.Errorf("#allocs was %f; want 1", n) } }) } }