1 // Copyright 2011 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.
17 "golang.org/x/text/internal/testtext"
18 "golang.org/x/text/transform"
22 testn = flag.Int("testn", -1, "specific test number to run or -1 for all")
25 // pc replaces any rune r that is repeated n times, for n > 1, with r{n}.
26 func pc(s string) []byte {
27 b := bytes.NewBuffer(make([]byte, 0, len(s)))
28 for i := 0; i < len(s); {
29 r, sz := utf8.DecodeRuneInString(s[i:])
32 // Special-case one-byte case to handle repetition for invalid UTF-8.
33 for c := s[i]; i+n < len(s) && s[i+n] == c; n++ {
36 for _, r2 := range s[i:] {
43 b.WriteString(s[i : i+sz])
45 fmt.Fprintf(b, "{%d}", n)
52 // pidx finds the index from which two strings start to differ, plus context.
53 // It returns the index and ellipsis if the index is greater than 0.
54 func pidx(a, b string) (i int, prefix string) {
55 for ; i < len(a) && i < len(b) && a[i] == b[i]; i++ {
60 i -= 3 // ensure taking at least one full rune before the difference.
61 for k := i - 7; i > k && !utf8.RuneStart(a[i]); i-- {
66 type PositionTest struct {
69 buffer string // expected contents of reorderBuffer, if applicable
72 type positionFunc func(rb *reorderBuffer, s string) (int, []byte)
74 func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) {
77 for i, test := range tests {
79 rb.src = inputString(test.input)
80 rb.nsrc = len(test.input)
81 pos, out := fn(&rb, test.input)
83 t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos)
85 if outs := string(out); outs != test.buffer {
86 k, pfx := pidx(outs, test.buffer)
87 t.Errorf("%s:%d: buffer \nwas %s%+q; \nwant %s%+q", name, i, pfx, pc(outs[k:]), pfx, pc(test.buffer[k:]))
92 func grave(n int) string {
96 func rep(r rune, n int) string {
97 return strings.Repeat(string(r), n)
100 const segSize = maxByteBufferSize
102 var cgj = GraphemeJoiner
104 var decomposeSegmentTests = []PositionTest{
108 {"\u00E0\x80", 2, "\u0061\u0300"},
112 // starter + composing
113 {"a\u0300", 3, "a\u0300"},
114 {"a\u0300b", 3, "a\u0300"},
115 // with decomposition
116 {"\u00C0", 2, "A\u0300"},
117 {"\u00C0b", 2, "A\u0300"},
119 {grave(31), 60, grave(30) + cgj},
120 {"a" + grave(31), 61, "a" + grave(30) + cgj},
122 // Stability tests: see http://www.unicode.org/review/pr-29.html.
123 // U+0300 COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;;
124 // U+0B47 ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
125 // U+0B3E ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
126 // U+1100 HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
127 // U+1161 HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
128 {"\u0B47\u0300\u0B3E", 8, "\u0B47\u0300\u0B3E"},
129 {"\u1100\u0300\u1161", 8, "\u1100\u0300\u1161"},
130 {"\u0B47\u0B3E", 6, "\u0B47\u0B3E"},
131 {"\u1100\u1161", 6, "\u1100\u1161"},
133 // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
134 // Sequence of decomposing characters that are starters and modifiers.
135 {"\u0d4a" + strings.Repeat("\u0d3e", 31), 90, "\u0d46" + strings.Repeat("\u0d3e", 30) + cgj},
137 {grave(30), 60, grave(30)},
138 // U+FF9E is a starter, but decomposes to U+3099, which is not.
139 {grave(30) + "\uff9e", 60, grave(30) + cgj},
140 // ends with incomplete UTF-8 encoding
142 {"\u0300\xCC", 2, "\u0300"},
145 func decomposeSegmentF(rb *reorderBuffer, s string) (int, []byte) {
146 rb.initString(NFD, s)
147 rb.setFlusher(nil, appendFlush)
148 p := decomposeSegment(rb, 0, true)
152 func TestDecomposeSegment(t *testing.T) {
153 runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests)
156 var firstBoundaryTests = []PositionTest{
160 {"\x80\x80", -1, ""},
163 {"\u0300\xff", 2, ""},
164 {"\u0300\xc0\x80\x80", 2, ""},
169 {"\u1103\u1161", 0, ""},
170 {"\u110B\u1173\u11B7", 0, ""},
171 {"\u1161\u110B\u1173\u11B7", 3, ""},
172 {"\u1173\u11B7\u1103\u1161", 6, ""},
173 // too many combining characters.
174 {grave(maxNonStarters - 1), -1, ""},
175 {grave(maxNonStarters), 60, ""},
176 {grave(maxNonStarters + 1), 60, ""},
179 func firstBoundaryF(rb *reorderBuffer, s string) (int, []byte) {
180 return rb.f.form.FirstBoundary([]byte(s)), nil
183 func firstBoundaryStringF(rb *reorderBuffer, s string) (int, []byte) {
184 return rb.f.form.FirstBoundaryInString(s), nil
187 func TestFirstBoundary(t *testing.T) {
188 runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests)
189 runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests)
192 func TestNextBoundary(t *testing.T) {
193 testCases := []struct {
202 {"\u0300", false, -1},
203 {"\x80\x80", true, 1},
204 {"\x80\x80", false, 1},
207 {"\u0300\xff", false, 2},
208 {"\u0300\xc0\x80\x80", false, 2},
209 {"\xc2\x80\x80", false, 2},
212 {"a\u0300\xc2", false, -1},
213 {"a\u0300\xc2", true, 3},
219 {"\u0300", false, -1},
220 {"\u0300a", false, 2},
222 {"\u1103\u1161", true, 6},
223 {"\u1103\u1161", false, -1},
224 {"\u110B\u1173\u11B7", false, -1},
225 {"\u110B\u1173\u11B7\u110B\u1173\u11B7", false, 9},
226 {"\u1161\u110B\u1173\u11B7", false, 3},
227 {"\u1173\u11B7\u1103\u1161", false, 6},
228 // too many combining characters.
229 {grave(maxNonStarters - 1), false, -1},
230 {grave(maxNonStarters), false, 60},
231 {grave(maxNonStarters + 1), false, 60},
234 for _, tc := range testCases {
235 if got := NFC.NextBoundary([]byte(tc.input), tc.atEOF); got != tc.want {
236 t.Errorf("NextBoundary(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want)
238 if got := NFC.NextBoundaryInString(tc.input, tc.atEOF); got != tc.want {
239 t.Errorf("NextBoundaryInString(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want)
244 var decomposeToLastTests = []PositionTest{
245 // ends with inert character
248 {"a\u0301\u0635", 5, ""},
249 // ends with non-inert starter
251 {"a\u0301a", 3, "a"},
252 {"a\u0301\u03B9", 3, "\u03B9"},
253 {"a\u0327", 0, "a\u0327"},
257 {"\xC0\x80\x80", 3, ""},
258 {"\xCC\x80\x80", 3, ""},
259 // ends with incomplete UTF-8 encoding
261 // ends with combining characters
262 {"\u0300\u0301", 0, "\u0300\u0301"},
263 {"a\u0300\u0301", 0, "a\u0300\u0301"},
264 {"a\u0301\u0308", 0, "a\u0301\u0308"},
265 {"a\u0308\u0301", 0, "a\u0308\u0301"},
266 {"aaaa\u0300\u0301", 3, "a\u0300\u0301"},
267 {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"},
268 {"\u00C0", 0, "A\u0300"},
269 {"a\u00C0", 1, "A\u0300"},
271 {"a\u0300\u00E0", 3, "a\u0300"},
272 // multisegment decompositions (flushes leading segments)
273 {"a\u0300\uFDC0", 7, "\u064A"},
274 {"\uFDC0" + grave(29), 4, "\u064A" + grave(29)},
275 {"\uFDC0" + grave(30), 4, "\u064A" + grave(30)},
276 {"\uFDC0" + grave(31), 5, grave(30)},
277 {"\uFDFA" + grave(14), 31, "\u0645" + grave(14)},
279 {"\u00E0" + grave(29), 0, "a" + grave(30)},
280 {"\u00E0" + grave(30), 2, grave(30)},
282 {"a\u1103", 1, "\u1103"},
283 {"a\u110B", 1, "\u110B"},
284 {"a\u110B\u1173", 1, "\u110B\u1173"},
285 // See comment in composition.go:compBoundaryAfter.
286 {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"},
287 {"a\uC73C", 1, "\u110B\u1173"},
288 {"다음", 3, "\u110B\u1173\u11B7"},
289 {"다", 0, "\u1103\u1161"},
290 {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"},
291 {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"},
292 {"다음음", 6, "\u110B\u1173\u11B7"},
293 {"음다다", 6, "\u1103\u1161"},
295 {"a" + grave(30), 0, "a" + grave(30)},
297 {"a" + grave(31), 3, grave(30)},
299 {"a\u0300\u11B7", 0, "a\u0300\u11B7"},
302 func decomposeToLast(rb *reorderBuffer, s string) (int, []byte) {
303 rb.setFlusher([]byte(s), appendFlush)
304 decomposeToLastBoundary(rb)
306 return len(rb.out), buf
309 func TestDecomposeToLastBoundary(t *testing.T) {
310 runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests)
313 var lastBoundaryTests = []PositionTest{
314 // ends with inert character
317 // ends with non-inert starter
322 {"a\xff\u0300", 1, ""}, // TODO: should probably be 2.
323 {"\xc0\x80\x80", 3, ""},
324 {"\xc0\x80\x80\u0300", 3, ""},
325 // ends with incomplete UTF-8 encoding
327 {"\xE0\x80", -1, ""},
328 {"\xF0\x80\x80", -1, ""},
332 // ends with combining characters
333 {"a\u0300\u0301", 0, ""},
334 {"aaaa\u0300\u0301", 3, ""},
335 {"\u0300a\u0300\u0301", 2, ""},
338 // decomposition may recombine
342 {"\u0300\u0301", -1, ""},
344 {"\x80\x80", -1, ""},
345 {"\x80\x80\u0301", -1, ""},
349 {"\u1103\u1161\u110B\u1173\u11B7", 6, ""},
350 {"\u110B\u1173\u11B7\u1103\u1161", 9, ""},
351 // too many combining characters.
352 {grave(maxNonStarters - 1), -1, ""},
353 // May still be preceded with a non-starter.
354 {grave(maxNonStarters), -1, ""},
355 // May still need to insert a cgj after the last combiner.
356 {grave(maxNonStarters + 1), 2, ""},
357 {grave(maxNonStarters + 2), 4, ""},
359 {"a" + grave(maxNonStarters-1), 0, ""},
360 {"a" + grave(maxNonStarters), 0, ""},
361 // May still need to insert a cgj after the last combiner.
362 {"a" + grave(maxNonStarters+1), 3, ""},
363 {"a" + grave(maxNonStarters+2), 5, ""},
366 func lastBoundaryF(rb *reorderBuffer, s string) (int, []byte) {
367 return rb.f.form.LastBoundary([]byte(s)), nil
370 func TestLastBoundary(t *testing.T) {
371 runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests)
374 type spanTest struct {
381 var quickSpanTests = []spanTest{
385 {"abc", true, 3, nil},
386 {"\u043Eb", true, 3, nil},
387 // incomplete last rune.
388 {"\xCC", true, 1, nil},
389 {"\xCC", false, 0, transform.ErrShortSrc},
390 {"a\xCC", true, 2, nil},
391 {"a\xCC", false, 0, transform.ErrShortSrc}, // TODO: could be 1 for NFD
392 // incorrectly ordered combining characters
393 {"\u0300\u0316", true, 0, transform.ErrEndOfSpan},
394 {"\u0300\u0316", false, 0, transform.ErrEndOfSpan},
395 {"\u0300\u0316cd", true, 0, transform.ErrEndOfSpan},
396 {"\u0300\u0316cd", false, 0, transform.ErrEndOfSpan},
397 // have a maximum number of combining characters.
398 {rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
399 {"a" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
400 {"Ɵ" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan},
401 {"aa" + rep(0x035D, 30) + "\u035B", true, 1, transform.ErrEndOfSpan},
402 {rep(0x035D, 30) + cgj + "\u035B", true, 64, nil},
403 {"a" + rep(0x035D, 30) + cgj + "\u035B", true, 65, nil},
404 {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil},
405 {"aa" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil},
407 {"a" + rep(0x035D, 30) + cgj + "\u035B", false, 61, transform.ErrShortSrc},
408 {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc},
409 {"aa" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc},
412 var quickSpanNFDTests = []spanTest{
414 {"\u00C0", true, 0, transform.ErrEndOfSpan},
415 {"abc\u00C0", true, 3, transform.ErrEndOfSpan},
416 // correctly ordered combining characters
417 {"\u0300", true, 2, nil},
418 {"ab\u0300", true, 4, nil},
419 {"ab\u0300cd", true, 6, nil},
420 {"\u0300cd", true, 4, nil},
421 {"\u0316\u0300", true, 4, nil},
422 {"ab\u0316\u0300", true, 6, nil},
423 {"ab\u0316\u0300cd", true, 8, nil},
424 {"ab\u0316\u0300\u00C0", true, 6, transform.ErrEndOfSpan},
425 {"\u0316\u0300cd", true, 6, nil},
426 {"\u043E\u0308b", true, 5, nil},
427 // incorrectly ordered combining characters
428 {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan}, // TODO: we could skip 'b' as well.
429 {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan},
431 {"같은", true, 0, transform.ErrEndOfSpan},
434 var quickSpanNFCTests = []spanTest{
436 {"\u00C0", true, 2, nil},
437 {"abc\u00C0", true, 5, nil},
438 // correctly ordered combining characters
439 // TODO: b may combine with modifiers, which is why this fails. We could
440 // make a more precise test that that actually checks whether last
441 // characters combines. Probably not worth it.
442 {"ab\u0300", true, 1, transform.ErrEndOfSpan},
443 {"ab\u0300cd", true, 1, transform.ErrEndOfSpan},
444 {"ab\u0316\u0300", true, 1, transform.ErrEndOfSpan},
445 {"ab\u0316\u0300cd", true, 1, transform.ErrEndOfSpan},
446 {"\u00C0\u035D", true, 4, nil},
447 // we do not special case leading combining characters
448 {"\u0300cd", true, 0, transform.ErrEndOfSpan},
449 {"\u0300", true, 0, transform.ErrEndOfSpan},
450 {"\u0316\u0300", true, 0, transform.ErrEndOfSpan},
451 {"\u0316\u0300cd", true, 0, transform.ErrEndOfSpan},
452 // incorrectly ordered combining characters
453 {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan},
454 {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan},
456 {"같은", true, 6, nil},
457 {"같은", false, 3, transform.ErrShortSrc},
458 // We return the start of the violating segment in case of overflow.
459 {grave(30) + "\uff9e", true, 0, transform.ErrEndOfSpan},
460 {grave(30), true, 0, transform.ErrEndOfSpan},
463 func runSpanTests(t *testing.T, name string, f Form, testCases []spanTest) {
464 for i, tc := range testCases {
465 s := fmt.Sprintf("Bytes/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF)
466 ok := testtext.Run(t, s, func(t *testing.T) {
467 n, err := f.Span([]byte(tc.input), tc.atEOF)
468 if n != tc.n || err != tc.err {
469 t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err)
473 continue // Don't do the String variant if the Bytes variant failed.
475 s = fmt.Sprintf("String/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF)
476 testtext.Run(t, s, func(t *testing.T) {
477 n, err := f.SpanString(tc.input, tc.atEOF)
478 if n != tc.n || err != tc.err {
479 t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err)
485 func TestSpan(t *testing.T) {
486 runSpanTests(t, "NFD", NFD, quickSpanTests)
487 runSpanTests(t, "NFD", NFD, quickSpanNFDTests)
488 runSpanTests(t, "NFC", NFC, quickSpanTests)
489 runSpanTests(t, "NFC", NFC, quickSpanNFCTests)
492 var isNormalTests = []PositionTest{
500 // incorrectly ordered combining characters
501 {"\u0300\u0316", 0, ""},
502 {"ab\u0300\u0316", 0, ""},
503 {"ab\u0300\u0316cd", 0, ""},
504 {"\u0300\u0316cd", 0, ""},
506 var isNormalNFDTests = []PositionTest{
509 {"abc\u00C0", 0, ""},
510 // correctly ordered combining characters
513 {"ab\u0300cd", 1, ""},
515 {"\u0316\u0300", 1, ""},
516 {"ab\u0316\u0300", 1, ""},
517 {"ab\u0316\u0300cd", 1, ""},
518 {"\u0316\u0300cd", 1, ""},
519 {"\u043E\u0308b", 1, ""},
523 var isNormalNFCTests = []PositionTest{
526 {"abc\u00C0", 1, ""},
529 {"a\u0300cd", 0, ""},
530 {"a\u0316\u0300", 0, ""},
531 {"a\u0316\u0300cd", 0, ""},
532 // correctly ordered combining characters
534 {"ab\u0300cd", 1, ""},
535 {"ab\u0316\u0300", 1, ""},
536 {"ab\u0316\u0300cd", 1, ""},
537 {"\u00C0\u035D", 1, ""},
539 {"\u0316\u0300cd", 1, ""},
544 var isNormalNFKXTests = []PositionTest{
549 func isNormalF(rb *reorderBuffer, s string) (int, []byte) {
550 if rb.f.form.IsNormal([]byte(s)) {
556 func isNormalStringF(rb *reorderBuffer, s string) (int, []byte) {
557 if rb.f.form.IsNormalString(s) {
563 func TestIsNormal(t *testing.T) {
564 runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests)
565 runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests)
566 runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests)
567 runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests)
568 runPosTests(t, "TestIsNormalNFKD1", NFKD, isNormalF, isNormalTests)
569 runPosTests(t, "TestIsNormalNFKD2", NFKD, isNormalF, isNormalNFDTests)
570 runPosTests(t, "TestIsNormalNFKD3", NFKD, isNormalF, isNormalNFKXTests)
571 runPosTests(t, "TestIsNormalNFKC1", NFKC, isNormalF, isNormalTests)
572 runPosTests(t, "TestIsNormalNFKC2", NFKC, isNormalF, isNormalNFCTests)
573 runPosTests(t, "TestIsNormalNFKC3", NFKC, isNormalF, isNormalNFKXTests)
576 func TestIsNormalString(t *testing.T) {
577 runPosTests(t, "TestIsNormalNFD1", NFD, isNormalStringF, isNormalTests)
578 runPosTests(t, "TestIsNormalNFD2", NFD, isNormalStringF, isNormalNFDTests)
579 runPosTests(t, "TestIsNormalNFC1", NFC, isNormalStringF, isNormalTests)
580 runPosTests(t, "TestIsNormalNFC2", NFC, isNormalStringF, isNormalNFCTests)
583 type AppendTest struct {
589 type appendFunc func(f Form, out []byte, s string) []byte
591 var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"}
593 func runNormTests(t *testing.T, name string, fn appendFunc) {
594 for f := NFC; f <= NFKD; f++ {
595 runAppendTests(t, name, f, fn, normTests[f])
599 func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) {
600 for i, test := range tests {
601 t.Run(fmt.Sprintf("%s/%d", fstr[f], i), func(t *testing.T) {
602 id := pc(test.left + test.right)
603 if *testn >= 0 && i != *testn {
606 t.Run("fn", func(t *testing.T) {
607 out := []byte(test.left)
608 have := string(fn(f, out, test.right))
609 if len(have) != len(test.out) {
610 t.Errorf("%+q: length is %d; want %d (%+q vs %+q)", id, len(have), len(test.out), pc(have), pc(test.out))
612 if have != test.out {
613 k, pf := pidx(have, test.out)
614 t.Errorf("%+q:\nwas %s%+q; \nwant %s%+q", id, pf, pc(have[k:]), pf, pc(test.out[k:]))
618 // Bootstrap by normalizing input. Ensures that the various variants
620 for g := NFC; g <= NFKD; g++ {
624 t.Run(fstr[g], func(t *testing.T) {
625 want := g.String(test.left + test.right)
626 have := string(fn(g, g.AppendString(nil, test.left), test.right))
627 if len(have) != len(want) {
628 t.Errorf("%+q: length is %d; want %d (%+q vs %+q)", id, len(have), len(want), pc(have), pc(want))
631 k, pf := pidx(have, want)
632 t.Errorf("%+q:\nwas %s%+q; \nwant %s%+q", id, pf, pc(have[k:]), pf, pc(want[k:]))
640 var normTests = [][]AppendTest{
647 var appendTestsNFC = []AppendTest{
649 {"", txt_all, txt_all},
650 {"\uff9e", grave(30), "\uff9e" + grave(29) + cgj + grave(1)},
651 {grave(30), "\uff9e", grave(30) + cgj + "\uff9e"},
653 // Tests designed for Iter.
654 { // ordering of non-composing combining characters
659 { // segment overflow
661 "a" + rep(0x0305, maxNonStarters+4) + "\u0316",
662 "a" + rep(0x0305, maxNonStarters) + cgj + "\u0316" + rep(0x305, 4),
665 { // Combine across non-blocking non-starters.
666 // U+0327 COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
667 // U+0325 COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
668 "", "a\u0327\u0325", "\u1e01\u0327",
671 { // Jamo V+T does not combine.
677 // Stability tests: see http://www.unicode.org/review/pr-29.html.
678 {"", "\u0b47\u0300\u0b3e", "\u0b47\u0300\u0b3e"},
679 {"", "\u1100\u0300\u1161", "\u1100\u0300\u1161"},
680 {"", "\u0b47\u0b3e", "\u0b4b"},
681 {"", "\u1100\u1161", "\uac00"},
683 // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
684 { // 0d4a starts a new segment.
686 "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15),
687 "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15),
690 { // Split combining characters.
691 // TODO: don't insert CGJ before starters.
693 "\u0d46" + strings.Repeat("\u0d3e", 31),
694 "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e",
697 { // Split combining characters.
699 "\u0d4a" + strings.Repeat("\u0d3e", 30),
700 "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e",
703 { // https://golang.org/issues/20079
709 { // https://golang.org/issues/20079
711 "\uac00" + strings.Repeat("\u0300", 30),
712 "\uac00" + strings.Repeat("\u0300", 29) + "\u034f\u0300",
715 { // https://golang.org/issues/20079
717 "\xeb" + strings.Repeat("\u0300", 31),
718 "\xeb" + strings.Repeat("\u0300", 30) + "\u034f\u0300",
722 var appendTestsNFD = []AppendTest{
723 // TODO: Move some of the tests here.
726 var appendTestsNFKC = []AppendTest{
731 {"", "\u0041\u0307\u0304", "\u01E0"},
732 // segment split across buffers
733 {"", "a\u0300b", "\u00E0b"},
734 {"a", "\u0300b", "\u00E0b"},
735 {"a", "\u0300\u0316", "\u00E0\u0316"},
736 {"a", "\u0316\u0300", "\u00E0\u0316"},
737 {"a", "\u0300a\u0300", "\u00E0\u00E0"},
738 {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"},
739 {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"},
740 {"a\u0300", "\u0327", "\u00E0\u0327"},
741 {"a\u0327", "\u0300", "\u00E0\u0327"},
742 {"a\u0316", "\u0300", "\u00E0\u0316"},
743 {"\u0041\u0307", "\u0304", "\u01E0"},
745 {"", "\u110B\u1173", "\uC73C"},
746 {"", "\u1103\u1161", "\uB2E4"},
747 {"", "\u110B\u1173\u11B7", "\uC74C"},
748 {"", "\u320E", "\x28\uAC00\x29"},
749 {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"},
750 {"\u1103", "\u1161", "\uB2E4"},
751 {"\u110B", "\u1173\u11B7", "\uC74C"},
752 {"\u110B\u1173", "\u11B7", "\uC74C"},
753 {"\uC73C", "\u11B7", "\uC74C"},
754 // UTF-8 encoding split across buffers
755 {"a\xCC", "\x80", "\u00E0"},
756 {"a\xCC", "\x80b", "\u00E0b"},
757 {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"},
758 {"a\xCC", "\x80\x80", "\u00E0\x80"},
759 {"a\xCC", "\x80\xCC", "\u00E0\xCC"},
760 {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"},
761 // ending in incomplete UTF-8 encoding
762 {"", "\xCC", "\xCC"},
763 {"a", "\xCC", "a\xCC"},
764 {"a", "b\xCC", "ab\xCC"},
765 {"\u0226", "\xCC", "\u0226\xCC"},
767 {"", "\x80", "\x80"},
768 {"", "\x80\x80\x80", "\x80\x80\x80"},
769 {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"},
770 {"", "a\x80", "a\x80"},
771 {"", "a\x80\x80\x80", "a\x80\x80\x80"},
772 {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"},
773 {"a", "\x80\x80\x80", "a\x80\x80\x80"},
775 {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)},
776 {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)},
777 {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)},
778 // overflow of combining characters
779 {"", grave(34), grave(30) + cgj + grave(4)},
780 {"", grave(36), grave(30) + cgj + grave(6)},
781 {grave(29), grave(5), grave(30) + cgj + grave(4)},
782 {grave(30), grave(4), grave(30) + cgj + grave(4)},
783 {grave(30), grave(3), grave(30) + cgj + grave(3)},
784 {grave(30) + "\xCC", "\x80", grave(30) + cgj + grave(1)},
785 {"", "\uFDFA" + grave(14), "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645" + grave(14)},
786 {"", "\uFDFA" + grave(28) + "\u0316", "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645\u0316" + grave(28)},
787 // - First rune has a trailing non-starter.
788 {"\u00d5", grave(30), "\u00d5" + grave(29) + cgj + grave(1)},
789 // - U+FF9E decomposes into a non-starter in compatibility mode. A CGJ must be
790 // inserted even when FF9E starts a new segment.
791 {"\uff9e", grave(30), "\u3099" + grave(29) + cgj + grave(1)},
792 {grave(30), "\uff9e", grave(30) + cgj + "\u3099"},
793 // - Many non-starter decompositions in a row causing overflow.
794 {"", rep(0x340, 31), rep(0x300, 30) + cgj + "\u0300"},
795 {"", rep(0xFF9E, 31), rep(0x3099, 30) + cgj + "\u3099"},
797 {"", "\u0644\u0625" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + "\u0300\u0300"},
798 {"", "\ufef9" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + rep(0x0300, 2)},
799 {"", "\ufef9" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + rep(0x0300, 2)},
801 // U+0F81 TIBETAN VOWEL SIGN REVERSED II splits into two modifiers.
802 {"", "\u0f7f" + rep(0xf71, 29) + "\u0f81", "\u0f7f" + rep(0xf71, 29) + cgj + "\u0f71\u0f80"},
803 {"", "\u0f7f" + rep(0xf71, 28) + "\u0f81", "\u0f7f" + rep(0xf71, 29) + "\u0f80"},
804 {"", "\u0f7f" + rep(0xf81, 16), "\u0f7f" + rep(0xf71, 15) + rep(0xf80, 15) + cgj + "\u0f71\u0f80"},
807 {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"},
808 {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"},
809 {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"},
810 {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"},
811 {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"},
812 {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
813 {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"},
814 {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
816 {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)},
818 {"", strings.Repeat("a\u0300\u0316", 31), strings.Repeat("\u00E0\u0316", 31)},
819 {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)},
820 {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)},
821 {"", "\u0041\u0307\u0304", "\u01E0"},
824 var appendTestsNFKD = []AppendTest{
825 {"", "a" + grave(64), "a" + grave(30) + cgj + grave(30) + cgj + grave(4)},
827 { // segment overflow on unchanged character
829 "a" + grave(64) + "\u0316",
830 "a" + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(4),
832 { // segment overflow on unchanged character + start value
834 "a" + grave(98) + "\u0316",
835 "a" + grave(30) + cgj + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(8),
837 { // segment overflow on decomposition. (U+0340 decomposes to U+0300.)
839 "a" + grave(59) + "\u0340",
840 "a" + grave(30) + cgj + grave(30),
842 { // segment overflow on non-starter decomposition
844 "a" + grave(33) + "\u0340" + grave(30) + "\u0320",
845 "a" + grave(30) + cgj + grave(30) + cgj + "\u0320" + grave(4),
847 { // start value after ASCII overflow
849 rep('a', segSize) + grave(32) + "\u0320",
850 rep('a', segSize) + grave(30) + cgj + "\u0320" + grave(2),
854 "\u1100\u1161" + grave(30) + "\u0320" + grave(2),
855 "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
864 "\uac00" + grave(32) + "\u0320",
865 "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
867 { // Hangul overflow in Hangul mode.
869 "\uac00\uac00" + grave(32) + "\u0320",
870 "\u1100\u1161\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3),
872 { // Hangul overflow in Hangul mode.
874 strings.Repeat("\uac00", 3) + grave(32) + "\u0320",
875 strings.Repeat("\u1100\u1161", 3) + grave(29) + cgj + "\u0320" + grave(3),
877 { // start value after cc=0
879 "您您" + grave(34) + "\u0320",
880 "您您" + grave(30) + cgj + "\u0320" + grave(4),
882 { // start value after normalization
884 "\u0300\u0320a" + grave(34) + "\u0320",
885 "\u0320\u0300a" + grave(30) + cgj + "\u0320" + grave(4),
888 // U+0F81 TIBETAN VOWEL SIGN REVERSED II splits into two modifiers.
890 "a\u0f7f" + rep(0xf71, 29) + "\u0f81",
891 "a\u0f7f" + rep(0xf71, 29) + cgj + "\u0f71\u0f80",
895 func TestAppend(t *testing.T) {
896 runNormTests(t, "Append", func(f Form, out []byte, s string) []byte {
897 return f.Append(out, []byte(s)...)
901 func TestAppendString(t *testing.T) {
902 runNormTests(t, "AppendString", func(f Form, out []byte, s string) []byte {
903 return f.AppendString(out, s)
907 func TestBytes(t *testing.T) {
908 runNormTests(t, "Bytes", func(f Form, out []byte, s string) []byte {
910 buf = append(buf, out...)
911 buf = append(buf, s...)
916 func TestString(t *testing.T) {
917 runNormTests(t, "String", func(f Form, out []byte, s string) []byte {
918 outs := string(out) + s
919 return []byte(f.String(outs))
923 func TestLinking(t *testing.T) {
927 import "golang.org/x/text/unicode/norm"
928 func main() { fmt.Println(norm.%s) }
930 baseline, errB := testtext.CodeSize(fmt.Sprintf(prog, "MaxSegmentSize"))
931 withTables, errT := testtext.CodeSize(fmt.Sprintf(prog, `NFC.String("")`))
932 if errB != nil || errT != nil {
933 t.Skipf("code size failed: %v and %v", errB, errT)
935 // Tables are at least 50K
936 if d := withTables - baseline; d < 50*1024 {
937 t.Errorf("tables appear not to be dropped: %d - %d = %d",
938 withTables, baseline, d)
942 func appendBench(f Form, in []byte) func() {
943 buf := make([]byte, 0, 4*len(in))
949 func bytesBench(f Form, in []byte) func() {
955 func iterBench(f Form, in []byte) func() {
965 func transformBench(f Form, in []byte) func() {
966 buf := make([]byte, 4*len(in))
968 if _, n, err := f.Transform(buf, in, true); err != nil || len(in) != n {
969 log.Panic(n, len(in), err)
974 func readerBench(f Form, in []byte) func() {
975 buf := make([]byte, 4*len(in))
977 r := f.Reader(bytes.NewReader(in))
988 func writerBench(f Form, in []byte) func() {
989 buf := make([]byte, 0, 4*len(in))
991 r := f.Writer(bytes.NewBuffer(buf))
992 if _, err := r.Write(in); err != nil {
998 func appendBenchmarks(bm []func(), f Form, in []byte) []func() {
999 bm = append(bm, appendBench(f, in))
1000 bm = append(bm, iterBench(f, in))
1001 bm = append(bm, transformBench(f, in))
1002 bm = append(bm, readerBench(f, in))
1003 bm = append(bm, writerBench(f, in))
1007 func doFormBenchmark(b *testing.B, inf, f Form, s string) {
1009 in := inf.Bytes([]byte(s))
1010 bm := appendBenchmarks(nil, f, in)
1011 b.SetBytes(int64(len(in) * len(bm)))
1013 for i := 0; i < b.N; i++ {
1014 for _, fn := range bm {
1020 func doSingle(b *testing.B, f func(Form, []byte) func(), s []byte) {
1023 b.SetBytes(int64(len(s)))
1025 for i := 0; i < b.N; i++ {
1031 smallNoChange = []byte("nörmalization")
1032 smallChange = []byte("No\u0308rmalization")
1033 ascii = strings.Repeat("There is nothing to change here! ", 500)
1036 func lowerBench(f Form, in []byte) func() {
1037 // Use package strings instead of bytes as it doesn't allocate memory
1038 // if there aren't any changes.
1045 func BenchmarkLowerCaseNoChange(b *testing.B) {
1046 doSingle(b, lowerBench, smallNoChange)
1048 func BenchmarkLowerCaseChange(b *testing.B) {
1049 doSingle(b, lowerBench, smallChange)
1052 func quickSpanBench(f Form, in []byte) func() {
1058 func BenchmarkQuickSpanChangeNFC(b *testing.B) {
1059 doSingle(b, quickSpanBench, smallNoChange)
1062 func BenchmarkBytesNoChangeNFC(b *testing.B) {
1063 doSingle(b, bytesBench, smallNoChange)
1065 func BenchmarkBytesChangeNFC(b *testing.B) {
1066 doSingle(b, bytesBench, smallChange)
1069 func BenchmarkAppendNoChangeNFC(b *testing.B) {
1070 doSingle(b, appendBench, smallNoChange)
1072 func BenchmarkAppendChangeNFC(b *testing.B) {
1073 doSingle(b, appendBench, smallChange)
1075 func BenchmarkAppendLargeNFC(b *testing.B) {
1076 doSingle(b, appendBench, txt_all_bytes)
1079 func BenchmarkIterNoChangeNFC(b *testing.B) {
1080 doSingle(b, iterBench, smallNoChange)
1082 func BenchmarkIterChangeNFC(b *testing.B) {
1083 doSingle(b, iterBench, smallChange)
1085 func BenchmarkIterLargeNFC(b *testing.B) {
1086 doSingle(b, iterBench, txt_all_bytes)
1089 func BenchmarkTransformNoChangeNFC(b *testing.B) {
1090 doSingle(b, transformBench, smallNoChange)
1092 func BenchmarkTransformChangeNFC(b *testing.B) {
1093 doSingle(b, transformBench, smallChange)
1095 func BenchmarkTransformLargeNFC(b *testing.B) {
1096 doSingle(b, transformBench, txt_all_bytes)
1099 func BenchmarkNormalizeAsciiNFC(b *testing.B) {
1100 doFormBenchmark(b, NFC, NFC, ascii)
1102 func BenchmarkNormalizeAsciiNFD(b *testing.B) {
1103 doFormBenchmark(b, NFC, NFD, ascii)
1105 func BenchmarkNormalizeAsciiNFKC(b *testing.B) {
1106 doFormBenchmark(b, NFC, NFKC, ascii)
1108 func BenchmarkNormalizeAsciiNFKD(b *testing.B) {
1109 doFormBenchmark(b, NFC, NFKD, ascii)
1112 func BenchmarkNormalizeNFC2NFC(b *testing.B) {
1113 doFormBenchmark(b, NFC, NFC, txt_all)
1115 func BenchmarkNormalizeNFC2NFD(b *testing.B) {
1116 doFormBenchmark(b, NFC, NFD, txt_all)
1118 func BenchmarkNormalizeNFD2NFC(b *testing.B) {
1119 doFormBenchmark(b, NFD, NFC, txt_all)
1121 func BenchmarkNormalizeNFD2NFD(b *testing.B) {
1122 doFormBenchmark(b, NFD, NFD, txt_all)
1125 // Hangul is often special-cased, so we test it separately.
1126 func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) {
1127 doFormBenchmark(b, NFC, NFC, txt_kr)
1129 func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) {
1130 doFormBenchmark(b, NFC, NFD, txt_kr)
1132 func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) {
1133 doFormBenchmark(b, NFD, NFC, txt_kr)
1135 func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) {
1136 doFormBenchmark(b, NFD, NFD, txt_kr)
1139 var forms = []Form{NFC, NFD, NFKC, NFKD}
1141 func doTextBenchmark(b *testing.B, s string) {
1145 for _, f := range forms {
1146 bm = appendBenchmarks(bm, f, in)
1148 b.SetBytes(int64(len(s) * len(bm)))
1150 for i := 0; i < b.N; i++ {
1151 for _, f := range bm {
1157 func BenchmarkCanonicalOrdering(b *testing.B) {
1158 doTextBenchmark(b, txt_canon)
1160 func BenchmarkExtendedLatin(b *testing.B) {
1161 doTextBenchmark(b, txt_vn)
1163 func BenchmarkMiscTwoByteUtf8(b *testing.B) {
1164 doTextBenchmark(b, twoByteUtf8)
1166 func BenchmarkMiscThreeByteUtf8(b *testing.B) {
1167 doTextBenchmark(b, threeByteUtf8)
1169 func BenchmarkHangul(b *testing.B) {
1170 doTextBenchmark(b, txt_kr)
1172 func BenchmarkJapanese(b *testing.B) {
1173 doTextBenchmark(b, txt_jp)
1175 func BenchmarkChinese(b *testing.B) {
1176 doTextBenchmark(b, txt_cn)
1178 func BenchmarkOverflow(b *testing.B) {
1179 doTextBenchmark(b, overflow)
1182 var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B"
1184 // Tests sampled from the Canonical ordering tests (Part 2) of
1185 // http://unicode.org/Public/UNIDATA/NormalizationTest.txt
1186 const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062
1187 \u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062
1188 \u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062
1189 \u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062
1190 \u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062
1191 \u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062
1192 \u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062
1193 \u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062
1194 \u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062
1195 \u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062
1196 \u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062
1197 \u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062
1198 \u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062
1199 \u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062
1200 \u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062
1201 \u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062
1202 \u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062
1203 \u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062`
1205 // Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/
1206 const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả.
1207 Nếu bạn sử dụng, chuyển đổi, hoặc xây dựng dự án từ
1208 nội dung được chia sẻ này, bạn phải áp dụng giấy phép này hoặc
1209 một giấy phép khác có các điều khoản tương tự như giấy phép này
1210 cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào
1211 trên đây cũng có thể được miễn bỏ nếu bạn được sự cho phép của
1212 người sở hữu bản quyền. Phạm vi công chúng — Khi tác phẩm hoặc
1213 bất kỳ chương nào của tác phẩm đã trong vùng dành cho công
1214 chúng theo quy định của pháp luật thì tình trạng của nó không
1215 bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.`
1217 // Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru
1218 const txt_ru = `При обязательном соблюдении следующих условий:
1219 Attribution — Вы должны атрибутировать произведение (указывать
1220 автора и источник) в порядке, предусмотренном автором или
1221 лицензиаром (но только так, чтобы никоим образом не подразумевалось,
1222 что они поддерживают вас или использование вами данного произведения).
1223 Υπό τις ακόλουθες προϋποθέσεις:`
1225 // Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/
1226 const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον
1227 τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια
1228 (χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή
1229 τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε,
1230 τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα
1231 μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή
1234 // Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar
1235 const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن
1236 تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من
1237 الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).
1238 المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة
1239 من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد
1242 // Taken from http://creativecommons.org/licenses/by-sa/1.0/il/
1243 const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן
1244 המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך
1245 שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות,
1246 לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך
1247 החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.`
1249 const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il
1251 // Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/
1252 const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시
1253 (Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의
1254 원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의
1255 이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다).
1256 동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본
1257 라이선스와 동일한 라이선스를 적용해야 합니다.`
1259 // Taken from http://creativecommons.org/licenses/by-sa/3.0/th/
1260 const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่
1261 มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่
1262 ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่
1263 คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื
1264 อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื
1265 อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น`
1267 const threeByteUtf8 = txt_th
1269 // Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/
1270 const txt_jp = `あなたの従うべき条件は以下の通りです。
1271 表示 — あなたは原著作者のクレジットを表示しなければなりません。
1272 継承 — もしあなたがこの作品を改変、変形または加工した場合、
1273 あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ
1276 // http://creativecommons.org/licenses/by-sa/2.5/cn/
1277 const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
1278 广播或通过信息网络传播本作品 创作演绎作品
1279 对本作品进行商业性使用 惟须遵守下列条件:
1280 署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
1281 相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
1282 您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
1284 const txt_cjk = txt_cn + txt_jp + txt_kr
1285 const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk
1287 var txt_all_bytes = []byte(txt_all)