github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/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  	"github.com/insionng/yougam/libraries/x/text/language"
    13  	"github.com/insionng/yougam/libraries/x/text/transform"
    14  	"github.com/insionng/yougam/libraries/x/text/unicode/norm"
    15  	"github.com/insionng/yougam/libraries/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 runeFoldData(r rune) (x struct{ simple, full, special string }) {
   146  	x = foldMap[r]
   147  	if x.simple == "" {
   148  		x.simple = string(unicode.ToLower(r))
   149  	}
   150  	if x.full == "" {
   151  		x.full = string(unicode.ToLower(r))
   152  	}
   153  	if x.special == "" {
   154  		x.special = x.full
   155  	}
   156  	return
   157  }
   158  
   159  func TestFoldData(t *testing.T) {
   160  	assigned := rangetable.Assigned(UnicodeVersion)
   161  	coreVersion := rangetable.Assigned(unicode.Version)
   162  	apply := func(r rune, f func(c *context) bool) (string, info) {
   163  		c := contextFromRune(r)
   164  		f(c)
   165  		return string(c.dst[:c.pDst]), c.info.cccType()
   166  	}
   167  	for r := rune(0); r <= lastRuneForTesting; r++ {
   168  		if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) {
   169  			continue
   170  		}
   171  		x := runeFoldData(r)
   172  		if got, info := apply(r, foldFull); got != x.full {
   173  			t.Errorf("full:%q (%U): got %q %U; want %q %U (ccc=%x)", r, r, got, []rune(got), x.full, []rune(x.full), info)
   174  		}
   175  		// TODO: special and simple.
   176  	}
   177  }
   178  
   179  func TestCCC(t *testing.T) {
   180  	assigned := rangetable.Assigned(UnicodeVersion)
   181  	normVersion := rangetable.Assigned(norm.Version)
   182  	for r := rune(0); r <= lastRuneForTesting; r++ {
   183  		if !unicode.In(r, assigned) || !unicode.In(r, normVersion) {
   184  			continue
   185  		}
   186  		c := contextFromRune(r)
   187  
   188  		p := norm.NFC.PropertiesString(string(r))
   189  		want := cccOther
   190  		switch p.CCC() {
   191  		case 0:
   192  			want = cccZero
   193  		case above:
   194  			want = cccAbove
   195  		}
   196  		if got := c.info.cccType(); got != want {
   197  			t.Errorf("%U: got %x; want %x", r, got, want)
   198  		}
   199  	}
   200  }
   201  
   202  func TestWordBreaks(t *testing.T) {
   203  	for i, tt := range breakTest {
   204  		parts := strings.Split(tt, "|")
   205  		want := ""
   206  		for _, s := range parts {
   207  			want += Title(language.Und).String(s)
   208  		}
   209  		src := strings.Join(parts, "")
   210  		got := Title(language.Und).String(src)
   211  		if got != want {
   212  			t.Errorf("%d: title(%q) = %q; want %q", i, src, got, want)
   213  		}
   214  	}
   215  }
   216  
   217  func TestContext(t *testing.T) {
   218  	tests := []struct {
   219  		desc       string
   220  		dstSize    int
   221  		atEOF      bool
   222  		src        string
   223  		out        string
   224  		nSrc       int
   225  		err        error
   226  		ops        string
   227  		prefixArg  string
   228  		prefixWant bool
   229  	}{{
   230  		desc:    "next: past end, atEOF, no checkpoint",
   231  		dstSize: 10,
   232  		atEOF:   true,
   233  		src:     "12",
   234  		out:     "",
   235  		nSrc:    2,
   236  		ops:     "next;next;next",
   237  		// Test that calling prefix with a non-empty argument when the buffer
   238  		// is depleted returns false.
   239  		prefixArg:  "x",
   240  		prefixWant: false,
   241  	}, {
   242  		desc:       "next: not at end, atEOF, no checkpoint",
   243  		dstSize:    10,
   244  		atEOF:      false,
   245  		src:        "12",
   246  		out:        "",
   247  		nSrc:       0,
   248  		err:        transform.ErrShortSrc,
   249  		ops:        "next;next",
   250  		prefixArg:  "",
   251  		prefixWant: true,
   252  	}, {
   253  		desc:       "next: past end, !atEOF, no checkpoint",
   254  		dstSize:    10,
   255  		atEOF:      false,
   256  		src:        "12",
   257  		out:        "",
   258  		nSrc:       0,
   259  		err:        transform.ErrShortSrc,
   260  		ops:        "next;next;next",
   261  		prefixArg:  "",
   262  		prefixWant: true,
   263  	}, {
   264  		desc:       "next: past end, !atEOF, checkpoint",
   265  		dstSize:    10,
   266  		atEOF:      false,
   267  		src:        "12",
   268  		out:        "",
   269  		nSrc:       2,
   270  		ops:        "next;next;checkpoint;next",
   271  		prefixArg:  "",
   272  		prefixWant: true,
   273  	}, {
   274  		desc:       "copy: exact count, atEOF, no checkpoint",
   275  		dstSize:    2,
   276  		atEOF:      true,
   277  		src:        "12",
   278  		out:        "12",
   279  		nSrc:       2,
   280  		ops:        "next;copy;next;copy;next",
   281  		prefixArg:  "",
   282  		prefixWant: true,
   283  	}, {
   284  		desc:       "copy: past end, !atEOF, no checkpoint",
   285  		dstSize:    2,
   286  		atEOF:      false,
   287  		src:        "12",
   288  		out:        "",
   289  		nSrc:       0,
   290  		err:        transform.ErrShortSrc,
   291  		ops:        "next;copy;next;copy;next",
   292  		prefixArg:  "",
   293  		prefixWant: true,
   294  	}, {
   295  		desc:       "copy: past end, !atEOF, checkpoint",
   296  		dstSize:    2,
   297  		atEOF:      false,
   298  		src:        "12",
   299  		out:        "12",
   300  		nSrc:       2,
   301  		ops:        "next;copy;next;copy;checkpoint;next",
   302  		prefixArg:  "",
   303  		prefixWant: true,
   304  	}, {
   305  		desc:       "copy: short dst",
   306  		dstSize:    1,
   307  		atEOF:      false,
   308  		src:        "12",
   309  		out:        "",
   310  		nSrc:       0,
   311  		err:        transform.ErrShortDst,
   312  		ops:        "next;copy;next;copy;checkpoint;next",
   313  		prefixArg:  "12",
   314  		prefixWant: false,
   315  	}, {
   316  		desc:       "copy: short dst, checkpointed",
   317  		dstSize:    1,
   318  		atEOF:      false,
   319  		src:        "12",
   320  		out:        "1",
   321  		nSrc:       1,
   322  		err:        transform.ErrShortDst,
   323  		ops:        "next;copy;checkpoint;next;copy;next",
   324  		prefixArg:  "",
   325  		prefixWant: true,
   326  	}, {
   327  		desc:       "writeString: simple",
   328  		dstSize:    3,
   329  		atEOF:      true,
   330  		src:        "1",
   331  		out:        "1ab",
   332  		nSrc:       1,
   333  		ops:        "next;copy;writeab;next",
   334  		prefixArg:  "",
   335  		prefixWant: true,
   336  	}, {
   337  		desc:       "writeString: short dst",
   338  		dstSize:    2,
   339  		atEOF:      true,
   340  		src:        "12",
   341  		out:        "",
   342  		nSrc:       0,
   343  		err:        transform.ErrShortDst,
   344  		ops:        "next;copy;writeab;next",
   345  		prefixArg:  "2",
   346  		prefixWant: true,
   347  	}, {
   348  		desc:       "writeString: simple",
   349  		dstSize:    3,
   350  		atEOF:      true,
   351  		src:        "12",
   352  		out:        "1ab",
   353  		nSrc:       2,
   354  		ops:        "next;copy;next;writeab;next",
   355  		prefixArg:  "",
   356  		prefixWant: true,
   357  	}, {
   358  		desc:       "writeString: short dst",
   359  		dstSize:    2,
   360  		atEOF:      true,
   361  		src:        "12",
   362  		out:        "",
   363  		nSrc:       0,
   364  		err:        transform.ErrShortDst,
   365  		ops:        "next;copy;next;writeab;next",
   366  		prefixArg:  "1",
   367  		prefixWant: false,
   368  	}, {
   369  		desc:    "prefix",
   370  		dstSize: 2,
   371  		atEOF:   true,
   372  		src:     "12",
   373  		out:     "",
   374  		nSrc:    0,
   375  		// Context will assign an ErrShortSrc if the input wasn't exhausted.
   376  		err:        transform.ErrShortSrc,
   377  		prefixArg:  "12",
   378  		prefixWant: true,
   379  	}}
   380  	for _, tt := range tests {
   381  		c := context{dst: make([]byte, tt.dstSize), src: []byte(tt.src), atEOF: tt.atEOF}
   382  
   383  		for _, op := range strings.Split(tt.ops, ";") {
   384  			switch op {
   385  			case "next":
   386  				c.next()
   387  			case "checkpoint":
   388  				c.checkpoint()
   389  			case "writeab":
   390  				c.writeString("ab")
   391  			case "copy":
   392  				c.copy()
   393  			case "":
   394  			default:
   395  				t.Fatalf("unknown op %q", op)
   396  			}
   397  		}
   398  		if got := c.hasPrefix(tt.prefixArg); got != tt.prefixWant {
   399  			t.Errorf("%s:\nprefix was %v; want %v", tt.desc, got, tt.prefixWant)
   400  		}
   401  		nDst, nSrc, err := c.ret()
   402  		if err != tt.err {
   403  			t.Errorf("%s:\nerror was %v; want %v", tt.desc, err, tt.err)
   404  		}
   405  		if out := string(c.dst[:nDst]); out != tt.out {
   406  			t.Errorf("%s:\nout was %q; want %q", tt.desc, out, tt.out)
   407  		}
   408  		if nSrc != tt.nSrc {
   409  			t.Errorf("%s:\nnSrc was %d; want %d", tt.desc, nSrc, tt.nSrc)
   410  		}
   411  	}
   412  }