github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/text/cases/context_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  	"strings"
     9  	"testing"
    10  	"unicode"
    11  
    12  	"golang.org/x/text/language"
    13  	"golang.org/x/text/transform"
    14  	"golang.org/x/text/unicode/norm"
    15  	"golang.org/x/text/unicode/rangetable"
    16  )
    17  
    18  // The following definitions are taken directly from Chapter 3 of The Unicode
    19  // Standard.
    20  
    21  func propCased(r rune) bool {
    22  	return propLower(r) || propUpper(r) || unicode.IsTitle(r)
    23  }
    24  
    25  func propLower(r rune) bool {
    26  	return unicode.IsLower(r) || unicode.Is(unicode.Other_Lowercase, r)
    27  }
    28  
    29  func propUpper(r rune) bool {
    30  	return unicode.IsUpper(r) || unicode.Is(unicode.Other_Uppercase, r)
    31  }
    32  
    33  func propIgnore(r rune) bool {
    34  	if unicode.In(r, unicode.Mn, unicode.Me, unicode.Cf, unicode.Lm, unicode.Sk) {
    35  		return true
    36  	}
    37  	return caseIgnorable[r]
    38  }
    39  
    40  func hasBreakProp(r rune) bool {
    41  	// binary search over ranges
    42  	lo := 0
    43  	hi := len(breakProp)
    44  	for lo < hi {
    45  		m := lo + (hi-lo)/2
    46  		bp := &breakProp[m]
    47  		if bp.lo <= r && r <= bp.hi {
    48  			return true
    49  		}
    50  		if r < bp.lo {
    51  			hi = m
    52  		} else {
    53  			lo = m + 1
    54  		}
    55  	}
    56  	return false
    57  }
    58  
    59  func contextFromRune(r rune) *context {
    60  	c := context{dst: make([]byte, 128), src: []byte(string(r)), atEOF: true}
    61  	c.next()
    62  	return &c
    63  }
    64  
    65  func TestCaseProperties(t *testing.T) {
    66  	assigned := rangetable.Assigned(UnicodeVersion)
    67  	coreVersion := rangetable.Assigned(unicode.Version)
    68  	for r := rune(0); r <= lastRuneForTesting; r++ {
    69  		if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) {
    70  			continue
    71  		}
    72  		c := contextFromRune(r)
    73  		if got, want := c.info.isCaseIgnorable(), propIgnore(r); got != want {
    74  			t.Errorf("caseIgnorable(%U): got %v; want %v (%x)", r, got, want, c.info)
    75  		}
    76  		// New letters may change case types, but existing case pairings should
    77  		// not change. See Case Pair Stability in
    78  		// http://unicode.org/policies/stability_policy.html.
    79  		if rf := unicode.SimpleFold(r); rf != r && unicode.In(rf, assigned) {
    80  			if got, want := c.info.isCased(), propCased(r); got != want {
    81  				t.Errorf("cased(%U): got %v; want %v (%x)", r, got, want, c.info)
    82  			}
    83  			if got, want := c.caseType() == cUpper, propUpper(r); got != want {
    84  				t.Errorf("upper(%U): got %v; want %v (%x)", r, got, want, c.info)
    85  			}
    86  			if got, want := c.caseType() == cLower, propLower(r); got != want {
    87  				t.Errorf("lower(%U): got %v; want %v (%x)", r, got, want, c.info)
    88  			}
    89  		}
    90  		if got, want := c.info.isBreak(), hasBreakProp(r); got != want {
    91  			t.Errorf("isBreak(%U): got %v; want %v (%x)", r, got, want, c.info)
    92  		}
    93  	}
    94  	// TODO: get title case from unicode file.
    95  }
    96  
    97  func TestMapping(t *testing.T) {
    98  	assigned := rangetable.Assigned(UnicodeVersion)
    99  	coreVersion := rangetable.Assigned(unicode.Version)
   100  	apply := func(r rune, f func(c *context) bool) string {
   101  		c := contextFromRune(r)
   102  		f(c)
   103  		return string(c.dst[:c.pDst])
   104  	}
   105  
   106  	for r, tt := range special {
   107  		if got, want := apply(r, lower), tt.toLower; got != want {
   108  			t.Errorf("lowerSpecial:(%U): got %+q; want %+q", r, got, want)
   109  		}
   110  		if got, want := apply(r, title), tt.toTitle; got != want {
   111  			t.Errorf("titleSpecial:(%U): got %+q; want %+q", r, got, want)
   112  		}
   113  		if got, want := apply(r, upper), tt.toUpper; got != want {
   114  			t.Errorf("upperSpecial:(%U): got %+q; want %+q", r, got, want)
   115  		}
   116  	}
   117  
   118  	for r := rune(0); r <= lastRuneForTesting; r++ {
   119  		if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) {
   120  			continue
   121  		}
   122  		if rf := unicode.SimpleFold(r); rf == r || !unicode.In(rf, assigned) {
   123  			continue
   124  		}
   125  		if _, ok := special[r]; ok {
   126  			continue
   127  		}
   128  		want := string(unicode.ToLower(r))
   129  		if got := apply(r, lower); got != want {
   130  			t.Errorf("lower:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
   131  		}
   132  
   133  		want = string(unicode.ToUpper(r))
   134  		if got := apply(r, upper); got != want {
   135  			t.Errorf("upper:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
   136  		}
   137  
   138  		want = string(unicode.ToTitle(r))
   139  		if got := apply(r, title); got != want {
   140  			t.Errorf("title:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want))
   141  		}
   142  	}
   143  }
   144  
   145  func TestCCC(t *testing.T) {
   146  	assigned := rangetable.Assigned(UnicodeVersion)
   147  	normVersion := rangetable.Assigned(norm.Version)
   148  	for r := rune(0); r <= lastRuneForTesting; r++ {
   149  		if !unicode.In(r, assigned) || !unicode.In(r, normVersion) {
   150  			continue
   151  		}
   152  		c := contextFromRune(r)
   153  
   154  		p := norm.NFC.PropertiesString(string(r))
   155  		want := cccOther
   156  		switch p.CCC() {
   157  		case 0:
   158  			want = cccZero
   159  		case above:
   160  			want = cccAbove
   161  		}
   162  		if got := c.info.cccType(); got != want {
   163  			t.Errorf("%U: got %x; want %x", r, got, want)
   164  		}
   165  	}
   166  }
   167  
   168  func TestWordBreaks(t *testing.T) {
   169  	for i, tt := range breakTest {
   170  		parts := strings.Split(tt, "|")
   171  		want := ""
   172  		for _, s := range parts {
   173  			want += Title(language.Und).String(s)
   174  		}
   175  		src := strings.Join(parts, "")
   176  		got := Title(language.Und).String(src)
   177  		if got != want {
   178  			t.Errorf("%d: title(%q) = %q; want %q", i, src, got, want)
   179  		}
   180  	}
   181  }
   182  
   183  func TestContext(t *testing.T) {
   184  	tests := []struct {
   185  		desc       string
   186  		dstSize    int
   187  		atEOF      bool
   188  		src        string
   189  		out        string
   190  		nSrc       int
   191  		err        error
   192  		ops        string
   193  		prefixArg  string
   194  		prefixWant bool
   195  	}{{
   196  		desc:    "next: past end, atEOF, no checkpoint",
   197  		dstSize: 10,
   198  		atEOF:   true,
   199  		src:     "12",
   200  		out:     "",
   201  		nSrc:    2,
   202  		ops:     "next;next;next",
   203  		// Test that calling prefix with a non-empty argument when the buffer
   204  		// is depleted returns false.
   205  		prefixArg:  "x",
   206  		prefixWant: false,
   207  	}, {
   208  		desc:       "next: not at end, atEOF, no checkpoint",
   209  		dstSize:    10,
   210  		atEOF:      false,
   211  		src:        "12",
   212  		out:        "",
   213  		nSrc:       0,
   214  		err:        transform.ErrShortSrc,
   215  		ops:        "next;next",
   216  		prefixArg:  "",
   217  		prefixWant: true,
   218  	}, {
   219  		desc:       "next: past end, !atEOF, no checkpoint",
   220  		dstSize:    10,
   221  		atEOF:      false,
   222  		src:        "12",
   223  		out:        "",
   224  		nSrc:       0,
   225  		err:        transform.ErrShortSrc,
   226  		ops:        "next;next;next",
   227  		prefixArg:  "",
   228  		prefixWant: true,
   229  	}, {
   230  		desc:       "next: past end, !atEOF, checkpoint",
   231  		dstSize:    10,
   232  		atEOF:      false,
   233  		src:        "12",
   234  		out:        "",
   235  		nSrc:       2,
   236  		ops:        "next;next;checkpoint;next",
   237  		prefixArg:  "",
   238  		prefixWant: true,
   239  	}, {
   240  		desc:       "copy: exact count, atEOF, no checkpoint",
   241  		dstSize:    2,
   242  		atEOF:      true,
   243  		src:        "12",
   244  		out:        "12",
   245  		nSrc:       2,
   246  		ops:        "next;copy;next;copy;next",
   247  		prefixArg:  "",
   248  		prefixWant: true,
   249  	}, {
   250  		desc:       "copy: past end, !atEOF, no checkpoint",
   251  		dstSize:    2,
   252  		atEOF:      false,
   253  		src:        "12",
   254  		out:        "",
   255  		nSrc:       0,
   256  		err:        transform.ErrShortSrc,
   257  		ops:        "next;copy;next;copy;next",
   258  		prefixArg:  "",
   259  		prefixWant: true,
   260  	}, {
   261  		desc:       "copy: past end, !atEOF, checkpoint",
   262  		dstSize:    2,
   263  		atEOF:      false,
   264  		src:        "12",
   265  		out:        "12",
   266  		nSrc:       2,
   267  		ops:        "next;copy;next;copy;checkpoint;next",
   268  		prefixArg:  "",
   269  		prefixWant: true,
   270  	}, {
   271  		desc:       "copy: short dst",
   272  		dstSize:    1,
   273  		atEOF:      false,
   274  		src:        "12",
   275  		out:        "",
   276  		nSrc:       0,
   277  		err:        transform.ErrShortDst,
   278  		ops:        "next;copy;next;copy;checkpoint;next",
   279  		prefixArg:  "12",
   280  		prefixWant: false,
   281  	}, {
   282  		desc:       "copy: short dst, checkpointed",
   283  		dstSize:    1,
   284  		atEOF:      false,
   285  		src:        "12",
   286  		out:        "1",
   287  		nSrc:       1,
   288  		err:        transform.ErrShortDst,
   289  		ops:        "next;copy;checkpoint;next;copy;next",
   290  		prefixArg:  "",
   291  		prefixWant: true,
   292  	}, {
   293  		desc:       "writeString: simple",
   294  		dstSize:    3,
   295  		atEOF:      true,
   296  		src:        "1",
   297  		out:        "1ab",
   298  		nSrc:       1,
   299  		ops:        "next;copy;writeab;next",
   300  		prefixArg:  "",
   301  		prefixWant: true,
   302  	}, {
   303  		desc:       "writeString: short dst",
   304  		dstSize:    2,
   305  		atEOF:      true,
   306  		src:        "12",
   307  		out:        "",
   308  		nSrc:       0,
   309  		err:        transform.ErrShortDst,
   310  		ops:        "next;copy;writeab;next",
   311  		prefixArg:  "2",
   312  		prefixWant: true,
   313  	}, {
   314  		desc:       "writeString: simple",
   315  		dstSize:    3,
   316  		atEOF:      true,
   317  		src:        "12",
   318  		out:        "1ab",
   319  		nSrc:       2,
   320  		ops:        "next;copy;next;writeab;next",
   321  		prefixArg:  "",
   322  		prefixWant: true,
   323  	}, {
   324  		desc:       "writeString: short dst",
   325  		dstSize:    2,
   326  		atEOF:      true,
   327  		src:        "12",
   328  		out:        "",
   329  		nSrc:       0,
   330  		err:        transform.ErrShortDst,
   331  		ops:        "next;copy;next;writeab;next",
   332  		prefixArg:  "1",
   333  		prefixWant: false,
   334  	}, {
   335  		desc:    "prefix",
   336  		dstSize: 2,
   337  		atEOF:   true,
   338  		src:     "12",
   339  		out:     "",
   340  		nSrc:    0,
   341  		// Context will assign an ErrShortSrc if the input wasn't exhausted.
   342  		err:        transform.ErrShortSrc,
   343  		prefixArg:  "12",
   344  		prefixWant: true,
   345  	}}
   346  	for _, tt := range tests {
   347  		c := context{dst: make([]byte, tt.dstSize), src: []byte(tt.src), atEOF: tt.atEOF}
   348  
   349  		for _, op := range strings.Split(tt.ops, ";") {
   350  			switch op {
   351  			case "next":
   352  				c.next()
   353  			case "checkpoint":
   354  				c.checkpoint()
   355  			case "writeab":
   356  				c.writeString("ab")
   357  			case "copy":
   358  				c.copy()
   359  			case "":
   360  			default:
   361  				t.Fatalf("unknown op %q", op)
   362  			}
   363  		}
   364  		if got := c.hasPrefix(tt.prefixArg); got != tt.prefixWant {
   365  			t.Errorf("%s:\nprefix was %v; want %v", tt.desc, got, tt.prefixWant)
   366  		}
   367  		nDst, nSrc, err := c.ret()
   368  		if err != tt.err {
   369  			t.Errorf("%s:\nerror was %v; want %v", tt.desc, err, tt.err)
   370  		}
   371  		if out := string(c.dst[:nDst]); out != tt.out {
   372  			t.Errorf("%s:\nout was %q; want %q", tt.desc, out, tt.out)
   373  		}
   374  		if nSrc != tt.nSrc {
   375  			t.Errorf("%s:\nnSrc was %d; want %d", tt.desc, nSrc, tt.nSrc)
   376  		}
   377  	}
   378  }