github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/text/cases/map_test.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cases
     6  
     7  import (
     8  	"bytes"
     9  	"strings"
    10  	"testing"
    11  
    12  	"golang.org/x/text/language"
    13  	"golang.org/x/text/transform"
    14  	"golang.org/x/text/unicode/norm"
    15  )
    16  
    17  type testCase struct {
    18  	lang  string
    19  	src   interface{} // string, []string, or nil to skip test
    20  	title interface{} // string, []string, or nil to skip test
    21  	lower interface{} // string, []string, or nil to skip test
    22  	upper interface{} // string, []string, or nil to skip test
    23  	opts  options
    24  }
    25  
    26  // We don't support the NoFinalSigma option, but we use it to test the
    27  // underlying lower casers and to be able to compare differences in performance.
    28  func noFinalSigma(o *options) {
    29  	o.noFinalSigma = true
    30  }
    31  
    32  var testCases = []testCase{
    33  	0: {
    34  		lang:  "und",
    35  		src:   "abc aBc ABC abC İsıI ΕΣΆΣ",
    36  		title: "Abc Abc Abc Abc İsıi Εσάσ",
    37  		lower: "abc abc abc abc i\u0307sıi εσάσ",
    38  		upper: "ABC ABC ABC ABC İSII ΕΣΆΣ",
    39  		opts:  getOpts(noFinalSigma),
    40  	},
    41  
    42  	1: {
    43  		lang:  "und",
    44  		src:   "abc aBc ABC abC İsıI ΕΣΆΣ Σ _Σ -Σ",
    45  		title: "Abc Abc Abc Abc İsıi Εσάς Σ _Σ -Σ",
    46  		lower: "abc abc abc abc i\u0307sıi εσάς σ _σ -σ",
    47  		upper: "ABC ABC ABC ABC İSII ΕΣΆΣ Σ _Σ -Σ",
    48  	},
    49  
    50  	2: { // Title cased runes.
    51  		lang:  supported,
    52  		src:   "DžA",
    53  		title: "Dža",
    54  		lower: "dža",
    55  		upper: "DŽA",
    56  	},
    57  
    58  	3: {
    59  		// Title breaking.
    60  		lang: supported,
    61  		src: []string{
    62  			"FOO CASE TEST",
    63  			"DON'T DO THiS",
    64  			"χωΡΊΣ χωΡΊΣ^a χωΡΊΣ:a χωΡΊΣ:^a χωΡΊΣ^ όμΩΣ Σ",
    65  			"with-hyphens",
    66  			"49ers 49ers",
    67  			`"capitalize a^a -hyphen 0X _u a_u:a`,
    68  			"MidNumLet a.b\u2018c\u2019d\u2024e\ufe52f\uff07f\uff0eg",
    69  			"MidNum a,b;c\u037ed\u0589e\u060cf\u2044g\ufe50h",
    70  			"\u0345 x\u3031x x\u05d0x \u05d0x a'.a a.a a4,a",
    71  		},
    72  		title: []string{
    73  			"Foo Case Test",
    74  			"Don't Do This",
    75  			"Χωρίς Χωρίσ^A Χωρίσ:a Χωρίσ:^A Χωρίς^ Όμως Σ",
    76  			"With-Hyphens",
    77  			// Note that 49Ers is correct according to the spec.
    78  			// TODO: provide some option to the user to treat different
    79  			// characters as cased.
    80  			"49Ers 49Ers",
    81  			`"Capitalize A^A -Hyphen 0X _U A_u:a`,
    82  			"Midnumlet A.b\u2018c\u2019d\u2024e\ufe52f\uff07f\uff0eg",
    83  			"Midnum A,B;C\u037eD\u0589E\u060cF\u2044G\ufe50H",
    84  			"\u0399 X\u3031X X\u05d0x \u05d0X A'.A A.a A4,A",
    85  		},
    86  	},
    87  
    88  	// TODO: These are known deviations from the options{} Unicode Word Breaking
    89  	// Algorithm.
    90  	// {
    91  	// 	"und",
    92  	// 	"x_\u3031_x a4,4a",
    93  	// 	"X_\u3031_x A4,4a", // Currently is "X_\U3031_X A4,4A".
    94  	// 	"x_\u3031_x a4,4a",
    95  	// 	"X_\u3031_X A4,4A",
    96  	// 	options{},
    97  	// },
    98  
    99  	4: {
   100  		// Tests title options
   101  		lang:  "und",
   102  		src:   "abc aBc ABC abC İsıI o'Brien",
   103  		title: "Abc ABc ABC AbC İsıI O'Brien",
   104  		opts:  getOpts(NoLower),
   105  	},
   106  
   107  	5: {
   108  		lang:  "el",
   109  		src:   "aBc ΟΔΌΣ Οδός Σο ΣΟ Σ oΣ ΟΣ σ ἕξ \u03ac",
   110  		title: "Abc Οδός Οδός Σο Σο Σ Oς Ος Σ Ἕξ \u0386",
   111  		lower: "abc οδός οδός σο σο σ oς ος σ ἕξ \u03ac",
   112  		upper: "ABC ΟΔΟΣ ΟΔΟΣ ΣΟ ΣΟ Σ OΣ ΟΣ Σ ΕΞ \u0391", // Uppercase removes accents
   113  	},
   114  
   115  	6: {
   116  		lang:  "tr az",
   117  		src:   "Isiİ İsıI I\u0307sIiİ İsıI\u0307 I\u0300\u0307",
   118  		title: "Isii İsıı I\u0307sıii İsıi I\u0300\u0307",
   119  		lower: "ısii isıı isıii isıi \u0131\u0300\u0307",
   120  		upper: "ISİİ İSII I\u0307SIİİ İSII\u0307 I\u0300\u0307",
   121  	},
   122  
   123  	7: {
   124  		lang:  "lt",
   125  		src:   "I Ï J J̈ Į Į̈ Ì Í Ĩ xi̇̈ xj̇̈ xį̇̈ xi̇̀ xi̇́ xi̇̃ XI XÏ XJ XJ̈ XĮ XĮ̈ XI̟̤",
   126  		title: "I Ï J J̈ Į Į̈ Ì Í Ĩ Xi̇̈ Xj̇̈ Xį̇̈ Xi̇̀ Xi̇́ Xi̇̃ Xi Xi̇̈ Xj Xj̇̈ Xį Xį̇̈ Xi̟̤",
   127  		lower: "i i̇̈ j j̇̈ į į̇̈ i̇̀ i̇́ i̇̃ xi̇̈ xj̇̈ xį̇̈ xi̇̀ xi̇́ xi̇̃ xi xi̇̈ xj xj̇̈ xį xį̇̈ xi̟̤",
   128  		upper: "I Ï J J̈ Į Į̈ Ì Í Ĩ XÏ XJ̈ XĮ̈ XÌ XÍ XĨ XI XÏ XJ XJ̈ XĮ XĮ̈ XI̟̤",
   129  	},
   130  
   131  	8: {
   132  		lang:  "lt",
   133  		src:   "\u012e\u0300 \u00cc i\u0307\u0300 i\u0307\u0301 i\u0307\u0303 i\u0307\u0308 i\u0300\u0307",
   134  		title: "\u012e\u0300 \u00cc \u00cc \u00cd \u0128 \u00cf I\u0300\u0307",
   135  		lower: "\u012f\u0307\u0300 i\u0307\u0300 i\u0307\u0300 i\u0307\u0301 i\u0307\u0303 i\u0307\u0308 i\u0300\u0307",
   136  		upper: "\u012e\u0300 \u00cc \u00cc \u00cd \u0128 \u00cf I\u0300\u0307",
   137  	},
   138  
   139  	9: {
   140  		lang:  "nl",
   141  		src:   "ijs IJs Ij Ijs İJ İJs aa aA 'ns 'S",
   142  		title: "IJs IJs IJ IJs İj İjs Aa Aa 'ns 's",
   143  	},
   144  
   145  	// Note: this specification is not currently part of CLDR. The same holds
   146  	// for the leading apostrophe handling for Dutch.
   147  	// See http://unicode.org/cldr/trac/ticket/7078.
   148  	10: {
   149  		lang:  "af",
   150  		src:   "wag 'n bietjie",
   151  		title: "Wag 'n Bietjie",
   152  		lower: "wag 'n bietjie",
   153  		upper: "WAG 'N BIETJIE",
   154  	},
   155  }
   156  
   157  func TestCaseMappings(t *testing.T) {
   158  	for i, tt := range testCases {
   159  		src, ok := tt.src.([]string)
   160  		if !ok {
   161  			src = strings.Split(tt.src.(string), " ")
   162  		}
   163  
   164  		for _, lang := range strings.Split(tt.lang, " ") {
   165  			tag := language.MustParse(lang)
   166  			testEntry := func(name string, mk func(language.Tag, options) transform.Transformer, gold interface{}) {
   167  				c := Caser{mk(tag, tt.opts)}
   168  				if gold != nil {
   169  					wants, ok := gold.([]string)
   170  					if !ok {
   171  						wants = strings.Split(gold.(string), " ")
   172  					}
   173  					for j, want := range wants {
   174  						if got := c.String(src[j]); got != want {
   175  							t.Errorf("%d:%s:\n%s.String(%+q):\ngot  %+q;\nwant %+q", i, lang, name, src[j], got, want)
   176  						}
   177  					}
   178  				}
   179  				dst := make([]byte, 256) // big enough to hold any result
   180  				src := []byte(strings.Join(src, " "))
   181  				v := testing.AllocsPerRun(20, func() {
   182  					c.Transform(dst, src, true)
   183  				})
   184  				if v > 1.1 {
   185  					t.Errorf("%d:%s:\n%s: number of allocs was %f; want 0", i, lang, name, v)
   186  				}
   187  			}
   188  			testEntry("Upper", makeUpper, tt.upper)
   189  			testEntry("Lower", makeLower, tt.lower)
   190  			testEntry("Title", makeTitle, tt.title)
   191  		}
   192  	}
   193  }
   194  
   195  // TestAlloc tests that some mapping methods should not cause any allocation.
   196  func TestAlloc(t *testing.T) {
   197  	dst := make([]byte, 256) // big enough to hold any result
   198  	src := []byte(txtNonASCII)
   199  
   200  	for i, f := range []func() Caser{
   201  		func() Caser { return Upper(language.Und) },
   202  		func() Caser { return Lower(language.Und) },
   203  		func() Caser { return Title(language.Und) },
   204  	} {
   205  		var c Caser
   206  		v := testing.AllocsPerRun(2, func() {
   207  			c = f()
   208  		})
   209  		if v > 1 {
   210  			// TODO: Right now only Upper has 1 allocation. Special-case Lower
   211  			// and Title as well to have less allocations for the root locale.
   212  			t.Skipf("%d:init: number of allocs was %f; want 0", i, v)
   213  		}
   214  		v = testing.AllocsPerRun(2, func() {
   215  			c.Transform(dst, src, true)
   216  		})
   217  		if v > 0 {
   218  			t.Errorf("%d:transform: number of allocs was %f; want 0", i, v)
   219  		}
   220  	}
   221  }
   222  
   223  func TestShortBuffersAndOverflow(t *testing.T) {
   224  	// minBufSize is the size of the buffer by which the casing operation in
   225  	// this package are guaranteed to make progress.
   226  	const minBufSize = norm.MaxSegmentSize
   227  
   228  	for i, tt := range []struct {
   229  		desc, src, want  string
   230  		firstErr         error
   231  		dstSize, srcSize int
   232  		t                transform.Transformer
   233  	}{{
   234  		desc:     "und upper: short dst",
   235  		src:      "abcdefg",
   236  		want:     "ABCDEFG",
   237  		firstErr: transform.ErrShortDst,
   238  		dstSize:  3,
   239  		srcSize:  minBufSize,
   240  		t:        Upper(language.Und),
   241  	}, {
   242  		desc:     "und upper: short src",
   243  		src:      "123é56",
   244  		want:     "123É56",
   245  		firstErr: transform.ErrShortSrc,
   246  		dstSize:  4,
   247  		srcSize:  4,
   248  		t:        Upper(language.Und),
   249  	}, {
   250  		desc:     "und upper: no error on short",
   251  		src:      "12",
   252  		want:     "12",
   253  		firstErr: nil,
   254  		dstSize:  1,
   255  		srcSize:  1,
   256  		t:        Upper(language.Und),
   257  	}, {
   258  		desc:     "und lower: short dst",
   259  		src:      "ABCDEFG",
   260  		want:     "abcdefg",
   261  		firstErr: transform.ErrShortDst,
   262  		dstSize:  3,
   263  		srcSize:  minBufSize,
   264  		t:        Lower(language.Und),
   265  	}, {
   266  		desc:     "und lower: short src",
   267  		src:      "123É56",
   268  		want:     "123é56",
   269  		firstErr: transform.ErrShortSrc,
   270  		dstSize:  4,
   271  		srcSize:  4,
   272  		t:        Lower(language.Und),
   273  	}, {
   274  		desc:     "und lower: no error on short",
   275  		src:      "12",
   276  		want:     "12",
   277  		firstErr: nil,
   278  		dstSize:  1,
   279  		srcSize:  1,
   280  		t:        Lower(language.Und),
   281  	}, {
   282  		desc:    "final sigma: no error",
   283  		src:     "ΟΣ",
   284  		want:    "Ος",
   285  		dstSize: minBufSize,
   286  		srcSize: minBufSize,
   287  		t:       Title(language.Und),
   288  	}, {
   289  		desc:     "final sigma: short source",
   290  		src:      "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
   291  		want:     "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
   292  		firstErr: transform.ErrShortSrc,
   293  		dstSize:  minBufSize,
   294  		srcSize:  10,
   295  		t:        Title(language.Und),
   296  	}, {
   297  		desc:     "final sigma: short destination 1",
   298  		src:      "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
   299  		want:     "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
   300  		firstErr: transform.ErrShortDst,
   301  		dstSize:  10,
   302  		srcSize:  minBufSize,
   303  		t:        Title(language.Und),
   304  	}, {
   305  		desc:     "final sigma: short destination 2",
   306  		src:      "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
   307  		want:     "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
   308  		firstErr: transform.ErrShortDst,
   309  		dstSize:  9,
   310  		srcSize:  minBufSize,
   311  		t:        Title(language.Und),
   312  	}, {
   313  		desc:     "final sigma: short destination 3",
   314  		src:      "ΟΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣ",
   315  		want:     "Οσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσσς",
   316  		firstErr: transform.ErrShortDst,
   317  		dstSize:  8,
   318  		srcSize:  minBufSize,
   319  		t:        Title(language.Und),
   320  	}, {
   321  		desc:     "clipped UTF-8 rune",
   322  		src:      "σσσσσσσσσσσ",
   323  		want:     "Σσσσσσσσσσσ",
   324  		firstErr: transform.ErrShortSrc,
   325  		dstSize:  minBufSize,
   326  		srcSize:  5,
   327  		t:        Title(language.Und),
   328  	}, {
   329  		desc:    "clipped UTF-8 rune atEOF",
   330  		src:     "σσσ" + string([]byte{0xC0}),
   331  		want:    "Σσσ" + string([]byte{0xC0}),
   332  		dstSize: minBufSize,
   333  		srcSize: minBufSize,
   334  		t:       Title(language.Und),
   335  	}, {
   336  		// Note: the choice to change the final sigma at the end in case of
   337  		// too many case ignorables is arbitrary. The main reason for this
   338  		// choice is that it results in simpler code.
   339  		desc:    "final sigma: max ignorables",
   340  		src:     "ΟΣ" + strings.Repeat(".", maxIgnorable) + "a",
   341  		want:    "Οσ" + strings.Repeat(".", maxIgnorable) + "a",
   342  		dstSize: minBufSize,
   343  		srcSize: minBufSize,
   344  		t:       Title(language.Und),
   345  	}, {
   346  		// Note: the choice to change the final sigma at the end in case of
   347  		// too many case ignorables is arbitrary. The main reason for this
   348  		// choice is that it results in simpler code.
   349  		desc:    "final sigma: too many ignorables",
   350  		src:     "ΟΣ" + strings.Repeat(".", maxIgnorable+1) + "a",
   351  		want:    "Ος" + strings.Repeat(".", maxIgnorable+1) + "a",
   352  		dstSize: minBufSize,
   353  		srcSize: len("ΟΣ" + strings.Repeat(".", maxIgnorable+1)),
   354  		t:       Title(language.Und),
   355  	}, {
   356  		desc:    "el upper: max ignorables",
   357  		src:     "ο" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0313",
   358  		want:    "Ο" + strings.Repeat("\u0321", maxIgnorable-1),
   359  		dstSize: minBufSize,
   360  		srcSize: minBufSize,
   361  		t:       Upper(language.Greek),
   362  	}, {
   363  		desc:    "el upper: too many ignorables",
   364  		src:     "ο" + strings.Repeat("\u0321", maxIgnorable) + "\u0313",
   365  		want:    "Ο" + strings.Repeat("\u0321", maxIgnorable) + "\u0313",
   366  		dstSize: minBufSize,
   367  		srcSize: len("ο" + strings.Repeat("\u0321", maxIgnorable)),
   368  		t:       Upper(language.Greek),
   369  	}, {
   370  		desc:     "el upper: short dst",
   371  		src:      "123ο",
   372  		want:     "123Ο",
   373  		firstErr: transform.ErrShortDst,
   374  		dstSize:  3,
   375  		srcSize:  minBufSize,
   376  		t:        Upper(language.Greek),
   377  	}, {
   378  		desc:    "lt lower: max ignorables",
   379  		src:     "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
   380  		want:    "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
   381  		dstSize: minBufSize,
   382  		srcSize: minBufSize,
   383  		t:       Lower(language.Lithuanian),
   384  	}, {
   385  		desc:    "lt lower: too many ignorables",
   386  		src:     "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0300",
   387  		want:    "i" + strings.Repeat("\u0321", maxIgnorable) + "\u0300",
   388  		dstSize: minBufSize,
   389  		srcSize: len("I" + strings.Repeat("\u0321", maxIgnorable)),
   390  		t:       Lower(language.Lithuanian),
   391  	}, {
   392  		desc:     "lt lower: decomposition with short dst buffer 1",
   393  		src:      "aaaaa\u00cc", // U+00CC LATIN CAPITAL LETTER I GRAVE
   394  		firstErr: transform.ErrShortDst,
   395  		want:     "aaaaai\u0307\u0300",
   396  		dstSize:  5,
   397  		srcSize:  minBufSize,
   398  		t:        Lower(language.Lithuanian),
   399  	}, {
   400  		desc:     "lt lower: decomposition with short dst buffer 2",
   401  		src:      "aaaa\u00cc", // U+00CC LATIN CAPITAL LETTER I GRAVE
   402  		firstErr: transform.ErrShortDst,
   403  		want:     "aaaai\u0307\u0300",
   404  		dstSize:  5,
   405  		srcSize:  minBufSize,
   406  		t:        Lower(language.Lithuanian),
   407  	}, {
   408  		desc:    "lt upper: max ignorables",
   409  		src:     "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
   410  		want:    "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
   411  		dstSize: minBufSize,
   412  		srcSize: minBufSize,
   413  		t:       Upper(language.Lithuanian),
   414  	}, {
   415  		desc:    "lt upper: too many ignorables",
   416  		src:     "i" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
   417  		want:    "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
   418  		dstSize: minBufSize,
   419  		srcSize: len("i" + strings.Repeat("\u0321", maxIgnorable)),
   420  		t:       Upper(language.Lithuanian),
   421  	}, {
   422  		desc:     "lt upper: short dst",
   423  		src:      "12i\u0307\u0300",
   424  		want:     "12\u00cc",
   425  		firstErr: transform.ErrShortDst,
   426  		dstSize:  3,
   427  		srcSize:  minBufSize,
   428  		t:        Upper(language.Lithuanian),
   429  	}, {
   430  		desc:    "aztr lower: max ignorables",
   431  		src:     "I" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0307\u0300",
   432  		want:    "i" + strings.Repeat("\u0321", maxIgnorable-1) + "\u0300",
   433  		dstSize: minBufSize,
   434  		srcSize: minBufSize,
   435  		t:       Lower(language.Turkish),
   436  	}, {
   437  		desc:    "aztr lower: too many ignorables",
   438  		src:     "I" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
   439  		want:    "\u0131" + strings.Repeat("\u0321", maxIgnorable) + "\u0307\u0300",
   440  		dstSize: minBufSize,
   441  		srcSize: len("I" + strings.Repeat("\u0321", maxIgnorable)),
   442  		t:       Lower(language.Turkish),
   443  	}, {
   444  		desc:     "nl title: pre-IJ cutoff",
   445  		src:      "  ij",
   446  		want:     "  IJ",
   447  		firstErr: transform.ErrShortDst,
   448  		dstSize:  2,
   449  		srcSize:  minBufSize,
   450  		t:        Title(language.Dutch),
   451  	}, {
   452  		desc:     "nl title: mid-IJ cutoff",
   453  		src:      "  ij",
   454  		want:     "  IJ",
   455  		firstErr: transform.ErrShortDst,
   456  		dstSize:  3,
   457  		srcSize:  minBufSize,
   458  		t:        Title(language.Dutch),
   459  	}} {
   460  		buf := make([]byte, tt.dstSize)
   461  		got := []byte{}
   462  		var nSrc, nDst int
   463  		var err error
   464  		for p := 0; p < len(tt.src); p += nSrc {
   465  			q := p + tt.srcSize
   466  			if q > len(tt.src) {
   467  				q = len(tt.src)
   468  			}
   469  			nDst, nSrc, err = tt.t.Transform(buf, []byte(tt.src[p:q]), q == len(tt.src))
   470  			got = append(got, buf[:nDst]...)
   471  
   472  			if p == 0 && err != tt.firstErr {
   473  				t.Errorf("%d:%s:\n error was %v; want %v", i, tt.desc, err, tt.firstErr)
   474  				break
   475  			}
   476  		}
   477  		if string(got) != tt.want {
   478  			t.Errorf("%d:%s:\ngot  %+q;\nwant %+q", i, tt.desc, got, tt.want)
   479  		}
   480  	}
   481  }
   482  
   483  var txtASCII = strings.Repeat("The quick brown fox jumps over the lazy dog. ", 50)
   484  
   485  // Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/
   486  const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả.  Nếu bạn sử
   487  dụng, chuyển đổi, hoặc xây dựng dự án từ  nội dung được chia sẻ này, bạn phải áp
   488  dụng giấy phép này hoặc  một giấy phép khác có các điều khoản tương tự như giấy
   489  phép này cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào trên đây
   490  cũng có thể được miễn bỏ nếu bạn được sự cho phép của người sở hữu bản quyền.
   491  Phạm vi công chúng — Khi tác phẩm hoặc bất kỳ chương nào của tác phẩm đã trong
   492  vùng dành cho công chúng theo quy định của pháp luật thì tình trạng của nó không
   493  bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.`
   494  
   495  // http://creativecommons.org/licenses/by-sa/2.5/cn/
   496  const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
   497  广播或通过信息网络传播本作品 创作演绎作品
   498  对本作品进行商业性使用 惟须遵守下列条件:
   499  署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
   500  相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
   501  您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
   502  
   503  // Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru
   504  const txt_ru = `При обязательном соблюдении следующих условий: Attribution — Вы
   505  должны атрибутировать произведение (указывать автора и источник) в порядке,
   506  предусмотренном автором или лицензиаром (но только так, чтобы никоим образом не
   507  подразумевалось, что они поддерживают вас или использование вами данного
   508  произведения). Υπό τις ακόλουθες προϋποθέσεις:`
   509  
   510  // Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/
   511  const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με
   512  τον τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια (χωρίς
   513  όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή τη χρήση του έργου
   514  από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε, τροποποιήσετε ή δημιουργήσετε
   515  περαιτέρω βασισμένοι στο έργο θα μπορείτε να διανέμετε το έργο που θα προκύψει
   516  μόνο με την ίδια ή παρόμοια άδεια.`
   517  
   518  const txtNonASCII = txt_vn + txt_cn + txt_ru + txt_gr
   519  
   520  // TODO: Improve ASCII performance.
   521  
   522  func benchFunc(b *testing.B, f func(b []byte) []byte, s string) {
   523  	src := []byte(s)
   524  	b.SetBytes(int64(len(src)))
   525  	for i := 0; i < b.N; i++ {
   526  		f(src)
   527  	}
   528  }
   529  
   530  func benchTransformer(b *testing.B, t transform.Transformer, s string) {
   531  	src := []byte(s)
   532  	dst := make([]byte, len(src))
   533  	b.SetBytes(int64(len(src)))
   534  
   535  	for i := 0; i < b.N; i++ {
   536  		t.Reset()
   537  		t.Transform(dst, src, true)
   538  	}
   539  }
   540  
   541  var (
   542  	noSigma = options{noFinalSigma: true}
   543  )
   544  
   545  func BenchmarkBytesToLower(b *testing.B) {
   546  	benchFunc(b, bytes.ToLower, txtNonASCII)
   547  }
   548  
   549  func BenchmarkSigmaLower(b *testing.B) {
   550  	benchTransformer(b, makeLower(language.Und, options{}), txtNonASCII)
   551  }
   552  
   553  func BenchmarkSimpleLower(b *testing.B) {
   554  	benchTransformer(b, makeLower(language.Und, noSigma), txtNonASCII)
   555  }
   556  
   557  func BenchmarkBytesToLowerASCII(b *testing.B) {
   558  	benchFunc(b, bytes.ToLower, txtASCII)
   559  }
   560  
   561  func BenchmarkSigmaLowerASCII(b *testing.B) {
   562  	benchTransformer(b, makeLower(language.Und, options{}), txtASCII)
   563  }
   564  
   565  func BenchmarkSimpleLowerASCII(b *testing.B) {
   566  	benchTransformer(b, makeLower(language.Und, noSigma), txtASCII)
   567  }
   568  
   569  func BenchmarkBytesToTitle(b *testing.B) {
   570  	benchFunc(b, bytes.ToTitle, txtNonASCII)
   571  }
   572  
   573  func BenchmarkSigmaTitle(b *testing.B) {
   574  	benchTransformer(b, makeTitle(language.Und, options{}), txtNonASCII)
   575  }
   576  
   577  func BenchmarkSimpleTitle(b *testing.B) {
   578  	benchTransformer(b, makeTitle(language.Und, noSigma), txtNonASCII)
   579  }
   580  
   581  func BenchmarkBytesToTitleASCII(b *testing.B) {
   582  	benchFunc(b, bytes.ToTitle, txtASCII)
   583  }
   584  
   585  func BenchmarkSigmaTitleASCII(b *testing.B) {
   586  	benchTransformer(b, makeTitle(language.Und, options{}), txtASCII)
   587  }
   588  
   589  func BenchmarkSimpleTitleASCII(b *testing.B) {
   590  	benchTransformer(b, makeTitle(language.Und, noSigma), txtASCII)
   591  }
   592  
   593  func BenchmarkBytesUpper(b *testing.B) {
   594  	benchFunc(b, bytes.ToUpper, txtNonASCII)
   595  }
   596  
   597  func BenchmarkUpper(b *testing.B) {
   598  	benchTransformer(b, Upper(language.Und), txtNonASCII)
   599  }
   600  
   601  func BenchmarkBytesUpperASCII(b *testing.B) {
   602  	benchFunc(b, bytes.ToUpper, txtASCII)
   603  }
   604  
   605  func BenchmarkUpperASCII(b *testing.B) {
   606  	benchTransformer(b, Upper(language.Und), txtASCII)
   607  }
   608  
   609  func BenchmarkUpperSmall(b *testing.B) {
   610  	benchTransformer(b, Upper(language.Und), "При")
   611  }
   612  
   613  func BenchmarkLowerSmall(b *testing.B) {
   614  	benchTransformer(b, Lower(language.Und), "При")
   615  }
   616  
   617  func BenchmarkTitleSmall(b *testing.B) {
   618  	benchTransformer(b, Title(language.Und), "при")
   619  }