github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/unicode/letter_test.gno (about)

     1  // Copyright 2009 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 unicode_test
     6  
     7  import (
     8  	"strings"
     9  	"testing"
    10  	uu "unicode"
    11  )
    12  
    13  var upperTest = []rune{
    14  	0x41,
    15  	0xc0,
    16  	0xd8,
    17  	0x100,
    18  	0x139,
    19  	0x14a,
    20  	0x178,
    21  	0x181,
    22  	0x376,
    23  	0x3cf,
    24  	0x13bd,
    25  	0x1f2a,
    26  	0x2102,
    27  	0x2c00,
    28  	0x2c10,
    29  	0x2c20,
    30  	0xa650,
    31  	0xa722,
    32  	0xff3a,
    33  	0x10400,
    34  	0x1d400,
    35  	0x1d7ca,
    36  }
    37  
    38  var notupperTest = []rune{
    39  	0x40,
    40  	0x5b,
    41  	0x61,
    42  	0x185,
    43  	0x1b0,
    44  	0x377,
    45  	0x387,
    46  	0x2150,
    47  	0xab7d,
    48  	0xffff,
    49  	0x10000,
    50  }
    51  
    52  var letterTest = []rune{
    53  	0x41,
    54  	0x61,
    55  	0xaa,
    56  	0xba,
    57  	0xc8,
    58  	0xdb,
    59  	0xf9,
    60  	0x2ec,
    61  	0x535,
    62  	0x620,
    63  	0x6e6,
    64  	0x93d,
    65  	0xa15,
    66  	0xb99,
    67  	0xdc0,
    68  	0xedd,
    69  	0x1000,
    70  	0x1200,
    71  	0x1312,
    72  	0x1401,
    73  	0x2c00,
    74  	0xa800,
    75  	0xf900,
    76  	0xfa30,
    77  	0xffda,
    78  	0xffdc,
    79  	0x10000,
    80  	0x10300,
    81  	0x10400,
    82  	0x20000,
    83  	0x2f800,
    84  	0x2fa1d,
    85  }
    86  
    87  var notletterTest = []rune{
    88  	0x20,
    89  	0x35,
    90  	0x375,
    91  	0x619,
    92  	0x700,
    93  	0x1885,
    94  	0xfffe,
    95  	0x1ffff,
    96  	0x10ffff,
    97  }
    98  
    99  // Contains all the special cased Latin-1 chars.
   100  var spaceTest = []rune{
   101  	0x09,
   102  	0x0a,
   103  	0x0b,
   104  	0x0c,
   105  	0x0d,
   106  	0x20,
   107  	0x85,
   108  	0xA0,
   109  	0x2000,
   110  	0x3000,
   111  }
   112  
   113  type caseT struct {
   114  	cas     int
   115  	in, out rune
   116  }
   117  
   118  var caseTest = []caseT{
   119  	// errors
   120  	{-1, '\n', 0xFFFD},
   121  	{uu.UpperCase, -1, -1},
   122  	{uu.UpperCase, 1 << 30, 1 << 30},
   123  
   124  	// ASCII (special-cased so test carefully)
   125  	{uu.UpperCase, '\n', '\n'},
   126  	{uu.UpperCase, 'a', 'A'},
   127  	{uu.UpperCase, 'A', 'A'},
   128  	{uu.UpperCase, '7', '7'},
   129  	{uu.LowerCase, '\n', '\n'},
   130  	{uu.LowerCase, 'a', 'a'},
   131  	{uu.LowerCase, 'A', 'a'},
   132  	{uu.LowerCase, '7', '7'},
   133  	{uu.TitleCase, '\n', '\n'},
   134  	{uu.TitleCase, 'a', 'A'},
   135  	{uu.TitleCase, 'A', 'A'},
   136  	{uu.TitleCase, '7', '7'},
   137  
   138  	// Latin-1: easy to read the tests!
   139  	{uu.UpperCase, 0x80, 0x80},
   140  	{uu.UpperCase, 'Å', 'Å'},
   141  	{uu.UpperCase, 'å', 'Å'},
   142  	{uu.LowerCase, 0x80, 0x80},
   143  	{uu.LowerCase, 'Å', 'å'},
   144  	{uu.LowerCase, 'å', 'å'},
   145  	{uu.TitleCase, 0x80, 0x80},
   146  	{uu.TitleCase, 'Å', 'Å'},
   147  	{uu.TitleCase, 'å', 'Å'},
   148  
   149  	// 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
   150  	{uu.UpperCase, 0x0131, 'I'},
   151  	{uu.LowerCase, 0x0131, 0x0131},
   152  	{uu.TitleCase, 0x0131, 'I'},
   153  
   154  	// 0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
   155  	{uu.UpperCase, 0x0133, 0x0132},
   156  	{uu.LowerCase, 0x0133, 0x0133},
   157  	{uu.TitleCase, 0x0133, 0x0132},
   158  
   159  	// 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
   160  	{uu.UpperCase, 0x212A, 0x212A},
   161  	{uu.LowerCase, 0x212A, 'k'},
   162  	{uu.TitleCase, 0x212A, 0x212A},
   163  
   164  	// From an UpperLower sequence
   165  	// A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
   166  	{uu.UpperCase, 0xA640, 0xA640},
   167  	{uu.LowerCase, 0xA640, 0xA641},
   168  	{uu.TitleCase, 0xA640, 0xA640},
   169  	// A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
   170  	{uu.UpperCase, 0xA641, 0xA640},
   171  	{uu.LowerCase, 0xA641, 0xA641},
   172  	{uu.TitleCase, 0xA641, 0xA640},
   173  	// A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
   174  	{uu.UpperCase, 0xA64E, 0xA64E},
   175  	{uu.LowerCase, 0xA64E, 0xA64F},
   176  	{uu.TitleCase, 0xA64E, 0xA64E},
   177  	// A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
   178  	{uu.UpperCase, 0xA65F, 0xA65E},
   179  	{uu.LowerCase, 0xA65F, 0xA65F},
   180  	{uu.TitleCase, 0xA65F, 0xA65E},
   181  
   182  	// From another UpperLower sequence
   183  	// 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
   184  	{uu.UpperCase, 0x0139, 0x0139},
   185  	{uu.LowerCase, 0x0139, 0x013A},
   186  	{uu.TitleCase, 0x0139, 0x0139},
   187  	// 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
   188  	{uu.UpperCase, 0x013f, 0x013f},
   189  	{uu.LowerCase, 0x013f, 0x0140},
   190  	{uu.TitleCase, 0x013f, 0x013f},
   191  	// 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
   192  	{uu.UpperCase, 0x0148, 0x0147},
   193  	{uu.LowerCase, 0x0148, 0x0148},
   194  	{uu.TitleCase, 0x0148, 0x0147},
   195  
   196  	// Lowercase lower than uppercase.
   197  	// AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8
   198  	{uu.UpperCase, 0xab78, 0x13a8},
   199  	{uu.LowerCase, 0xab78, 0xab78},
   200  	{uu.TitleCase, 0xab78, 0x13a8},
   201  	{uu.UpperCase, 0x13a8, 0x13a8},
   202  	{uu.LowerCase, 0x13a8, 0xab78},
   203  	{uu.TitleCase, 0x13a8, 0x13a8},
   204  
   205  	// Last block in the 5.1.0 table
   206  	// 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
   207  	{uu.UpperCase, 0x10400, 0x10400},
   208  	{uu.LowerCase, 0x10400, 0x10428},
   209  	{uu.TitleCase, 0x10400, 0x10400},
   210  	// 10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
   211  	{uu.UpperCase, 0x10427, 0x10427},
   212  	{uu.LowerCase, 0x10427, 0x1044F},
   213  	{uu.TitleCase, 0x10427, 0x10427},
   214  	// 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
   215  	{uu.UpperCase, 0x10428, 0x10400},
   216  	{uu.LowerCase, 0x10428, 0x10428},
   217  	{uu.TitleCase, 0x10428, 0x10400},
   218  	// 1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
   219  	{uu.UpperCase, 0x1044F, 0x10427},
   220  	{uu.LowerCase, 0x1044F, 0x1044F},
   221  	{uu.TitleCase, 0x1044F, 0x10427},
   222  
   223  	// First one not in the 5.1.0 table
   224  	// 10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
   225  	{uu.UpperCase, 0x10450, 0x10450},
   226  	{uu.LowerCase, 0x10450, 0x10450},
   227  	{uu.TitleCase, 0x10450, 0x10450},
   228  
   229  	// Non-letters with case.
   230  	{uu.LowerCase, 0x2161, 0x2171},
   231  	{uu.UpperCase, 0x0345, 0x0399},
   232  }
   233  
   234  func TestIsLetter(t *testing.T) {
   235  	for _, r := range upperTest {
   236  		if !uu.IsLetter(r) {
   237  			t.Errorf("IsLetter(U+%04X) = false, want true", r)
   238  		}
   239  	}
   240  	for _, r := range letterTest {
   241  		if !uu.IsLetter(r) {
   242  			t.Errorf("IsLetter(U+%04X) = false, want true", r)
   243  		}
   244  	}
   245  	for _, r := range notletterTest {
   246  		if uu.IsLetter(r) {
   247  			t.Errorf("IsLetter(U+%04X) = true, want false", r)
   248  		}
   249  	}
   250  }
   251  
   252  func TestIsUpper(t *testing.T) {
   253  	for _, r := range upperTest {
   254  		if !uu.IsUpper(r) {
   255  			t.Errorf("IsUpper(U+%04X) = false, want true", r)
   256  		}
   257  	}
   258  	for _, r := range notupperTest {
   259  		if uu.IsUpper(r) {
   260  			t.Errorf("IsUpper(U+%04X) = true, want false", r)
   261  		}
   262  	}
   263  	for _, r := range notletterTest {
   264  		if uu.IsUpper(r) {
   265  			t.Errorf("IsUpper(U+%04X) = true, want false", r)
   266  		}
   267  	}
   268  }
   269  
   270  func caseString(c int) string {
   271  	switch c {
   272  	case uu.UpperCase:
   273  		return "uu.UpperCase"
   274  	case uu.LowerCase:
   275  		return "uu.LowerCase"
   276  	case uu.TitleCase:
   277  		return "uu.TitleCase"
   278  	}
   279  	return "ErrorCase"
   280  }
   281  
   282  func TestTo(t *testing.T) {
   283  	for _, c := range caseTest {
   284  		r := uu.To(c.cas, c.in)
   285  		if c.out != r {
   286  			t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X", c.in, caseString(c.cas), r, c.out)
   287  		}
   288  	}
   289  }
   290  
   291  func TestToUpperCase(t *testing.T) {
   292  	for _, c := range caseTest {
   293  		if c.cas != uu.UpperCase {
   294  			continue
   295  		}
   296  		r := uu.ToUpper(c.in)
   297  		if c.out != r {
   298  			t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
   299  		}
   300  	}
   301  }
   302  
   303  func TestToLowerCase(t *testing.T) {
   304  	for _, c := range caseTest {
   305  		if c.cas != uu.LowerCase {
   306  			continue
   307  		}
   308  		r := uu.ToLower(c.in)
   309  		if c.out != r {
   310  			t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
   311  		}
   312  	}
   313  }
   314  
   315  func TestToTitleCase(t *testing.T) {
   316  	for _, c := range caseTest {
   317  		if c.cas != uu.TitleCase {
   318  			continue
   319  		}
   320  		r := uu.ToTitle(c.in)
   321  		if c.out != r {
   322  			t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
   323  		}
   324  	}
   325  }
   326  
   327  func TestIsSpace(t *testing.T) {
   328  	for _, c := range spaceTest {
   329  		if !uu.IsSpace(c) {
   330  			t.Errorf("IsSpace(U+%04X) = false; want true", c)
   331  		}
   332  	}
   333  	for _, c := range letterTest {
   334  		if uu.IsSpace(c) {
   335  			t.Errorf("IsSpace(U+%04X) = true; want false", c)
   336  		}
   337  	}
   338  }
   339  
   340  // Check that the optimizations for IsLetter etc. agree with the tables.
   341  // We only need to check the Latin-1 range.
   342  func TestLetterOptimizations(t *testing.T) {
   343  	for i := rune(0); i <= uu.MaxLatin1; i++ {
   344  		if uu.Is(uu.Letter, i) != uu.IsLetter(i) {
   345  			t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
   346  		}
   347  		if uu.Is(uu.Upper, i) != uu.IsUpper(i) {
   348  			t.Errorf("IsUpper(U+%04X) disagrees with Is(Upper)", i)
   349  		}
   350  		if uu.Is(uu.Lower, i) != uu.IsLower(i) {
   351  			t.Errorf("IsLower(U+%04X) disagrees with Is(Lower)", i)
   352  		}
   353  		if uu.Is(uu.Title, i) != uu.IsTitle(i) {
   354  			t.Errorf("IsTitle(U+%04X) disagrees with Is(Title)", i)
   355  		}
   356  		if uu.Is(uu.White_Space, i) != uu.IsSpace(i) {
   357  			t.Errorf("IsSpace(U+%04X) disagrees with Is(White_Space)", i)
   358  		}
   359  		if uu.To(uu.UpperCase, i) != uu.ToUpper(i) {
   360  			t.Errorf("ToUpper(U+%04X) disagrees with To(Upper)", i)
   361  		}
   362  		if uu.To(uu.LowerCase, i) != uu.ToLower(i) {
   363  			t.Errorf("ToLower(U+%04X) disagrees with To(Lower)", i)
   364  		}
   365  		if uu.To(uu.TitleCase, i) != uu.ToTitle(i) {
   366  			t.Errorf("ToTitle(U+%04X) disagrees with To(Title)", i)
   367  		}
   368  	}
   369  }
   370  
   371  func TestTurkishCase(t *testing.T) {
   372  	lower := []rune("abcçdefgğhıijklmnoöprsştuüvyz")
   373  	upper := []rune("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
   374  	for i, l := range lower {
   375  		u := upper[i]
   376  		if uu.TurkishCase.ToLower(l) != l {
   377  			t.Errorf("lower(U+%04X) is U+%04X not U+%04X", l, uu.TurkishCase.ToLower(l), l)
   378  		}
   379  		if uu.TurkishCase.ToUpper(u) != u {
   380  			t.Errorf("upper(U+%04X) is U+%04X not U+%04X", u, uu.TurkishCase.ToUpper(u), u)
   381  		}
   382  		if uu.TurkishCase.ToUpper(l) != u {
   383  			t.Errorf("upper(U+%04X) is U+%04X not U+%04X", l, uu.TurkishCase.ToUpper(l), u)
   384  		}
   385  		if uu.TurkishCase.ToLower(u) != l {
   386  			t.Errorf("lower(U+%04X) is U+%04X not U+%04X", u, uu.TurkishCase.ToLower(l), l)
   387  		}
   388  		if uu.TurkishCase.ToTitle(u) != u {
   389  			t.Errorf("title(U+%04X) is U+%04X not U+%04X", u, uu.TurkishCase.ToTitle(u), u)
   390  		}
   391  		if uu.TurkishCase.ToTitle(l) != u {
   392  			t.Errorf("title(U+%04X) is U+%04X not U+%04X", l, uu.TurkishCase.ToTitle(l), u)
   393  		}
   394  	}
   395  }
   396  
   397  var simpleFoldTests = []string{
   398  	// SimpleFold(x) returns the next equivalent rune > x or wraps
   399  	// around to smaller values.
   400  
   401  	// Easy cases.
   402  	"Aa",
   403  	"δΔ",
   404  
   405  	// ASCII special cases.
   406  	"KkK",
   407  	"Ssſ",
   408  
   409  	// Non-ASCII special cases.
   410  	"ρϱΡ",
   411  	"ͅΙιι",
   412  
   413  	// Extra special cases: has lower/upper but no case fold.
   414  	"İ",
   415  	"ı",
   416  
   417  	// Upper comes before lower (Cherokee).
   418  	"\u13b0\uab80",
   419  }
   420  
   421  func TestSimpleFold(t *testing.T) {
   422  	for _, tt := range simpleFoldTests {
   423  		cycle := []rune(tt)
   424  		r := cycle[len(cycle)-1]
   425  		for _, out := range cycle {
   426  			if r := uu.SimpleFold(r); r != out {
   427  				t.Errorf("SimpleFold(%#U) = %#U, want %#U", r, r, out)
   428  			}
   429  			r = out
   430  		}
   431  	}
   432  
   433  	if r := uu.SimpleFold(-42); r != -42 {
   434  		t.Errorf("SimpleFold(-42) = %v, want -42", r)
   435  	}
   436  }
   437  
   438  /* REMOVED FOR GNO
   439  // Running 'go test -calibrate' runs the calibration to find a plausible
   440  // cutoff point for linear search of a range list vs. binary search.
   441  // We create a fake table and then time how long it takes to do a
   442  // sequence of searches within that table, for all possible inputs
   443  // relative to the ranges (something before all, in each, between each, after all).
   444  // This assumes that all possible runes are equally likely.
   445  // In practice most runes are ASCII so this is a conservative estimate
   446  // of an effective cutoff value. In practice we could probably set it higher
   447  // than what this function recommends.
   448  
   449  var calibrate = flag.Bool("calibrate", false, "compute crossover for linear vs. binary search")
   450  
   451  func TestCalibrate(t *testing.T) {
   452  	if !*calibrate {
   453  		return
   454  	}
   455  
   456  	if runtime.GOARCH == "amd64" {
   457  		fmt.Printf("warning: running calibration on %s\n", runtime.GOARCH)
   458  	}
   459  
   460  	// Find the point where binary search wins by more than 10%.
   461  	// The 10% bias gives linear search an edge when they're close,
   462  	// because on predominantly ASCII inputs linear search is even
   463  	// better than our benchmarks measure.
   464  	n := sort.Search(64, func(n int) bool {
   465  		tab := fakeTable(n)
   466  		blinear := func(b *testing.B) {
   467  			tab := tab
   468  			max := n*5 + 20
   469  			for i := 0; i < b.N; i++ {
   470  				for j := 0; j <= max; j++ {
   471  					linear(tab, uint16(j))
   472  				}
   473  			}
   474  		}
   475  		bbinary := func(b *testing.B) {
   476  			tab := tab
   477  			max := n*5 + 20
   478  			for i := 0; i < b.N; i++ {
   479  				for j := 0; j <= max; j++ {
   480  					binary(tab, uint16(j))
   481  				}
   482  			}
   483  		}
   484  		bmlinear := testing.Benchmark(blinear)
   485  		bmbinary := testing.Benchmark(bbinary)
   486  		fmt.Printf("n=%d: linear=%d binary=%d\n", n, bmlinear.NsPerOp(), bmbinary.NsPerOp())
   487  		return bmlinear.NsPerOp()*100 > bmbinary.NsPerOp()*110
   488  	})
   489  	fmt.Printf("calibration: linear cutoff = %d\n", n)
   490  }
   491  */
   492  
   493  func fakeTable(n int) []uu.Range16 {
   494  	var r16 []uu.Range16
   495  	for i := 0; i < n; i++ {
   496  		r16 = append(r16, uu.Range16{uint16(i*5 + 10), uint16(i*5 + 12), 1})
   497  	}
   498  	return r16
   499  }
   500  
   501  func linear(ranges []uu.Range16, r uint16) bool {
   502  	for i := range ranges {
   503  		range_ := &ranges[i]
   504  		if r < range_.Lo {
   505  			return false
   506  		}
   507  		if r <= range_.Hi {
   508  			return (r-range_.Lo)%range_.Stride == 0
   509  		}
   510  	}
   511  	return false
   512  }
   513  
   514  func binary(ranges []uu.Range16, r uint16) bool {
   515  	// binary search over ranges
   516  	lo := 0
   517  	hi := len(ranges)
   518  	for lo < hi {
   519  		m := lo + (hi-lo)/2
   520  		range_ := &ranges[m]
   521  		if range_.Lo <= r && r <= range_.Hi {
   522  			return (r-range_.Lo)%range_.Stride == 0
   523  		}
   524  		if r < range_.Lo {
   525  			hi = m
   526  		} else {
   527  			lo = m + 1
   528  		}
   529  	}
   530  	return false
   531  }
   532  
   533  func TestLatinOffset(t *testing.T) {
   534  	maps := []map[string]*uu.RangeTable{
   535  		uu.Categories,
   536  		uu.FoldCategory,
   537  		uu.FoldScript,
   538  		uu.Properties,
   539  		uu.Scripts,
   540  	}
   541  	for _, m := range maps {
   542  		for name, tab := range m {
   543  			i := 0
   544  			for i < len(tab.R16) && tab.R16[i].Hi <= uu.MaxLatin1 {
   545  				i++
   546  			}
   547  			if tab.LatinOffset != i {
   548  				t.Errorf("%s: LatinOffset=%d, want %d", name, tab.LatinOffset, i)
   549  			}
   550  		}
   551  	}
   552  }
   553  
   554  func TestSpecialCaseNoMapping(t *testing.T) {
   555  	// Issue 25636
   556  	// no change for rune 'A', zero delta, under upper/lower/title case change.
   557  	noChangeForCapitalA := uu.CaseRange{'A', 'A', [uu.MaxCase]rune{0, 0, 0}}
   558  	got := strings.ToLowerSpecial(uu.SpecialCase([]uu.CaseRange{noChangeForCapitalA}), "ABC")
   559  	want := "Abc"
   560  	if got != want {
   561  		t.Errorf("got %q; want %q", got, want)
   562  	}
   563  }
   564  
   565  func TestNegativeRune(t *testing.T) {
   566  	// Issue 43254
   567  	// These tests cover negative rune handling by testing values which,
   568  	// when cast to uint8 or uint16, look like a particular valid rune.
   569  	// This package has Latin-1-specific optimizations, so we test all of
   570  	// Latin-1 and representative non-Latin-1 values in the character
   571  	// categories covered by IsGraphic, etc.
   572  	nonLatin1 := []uint32{
   573  		// Lu: LATIN CAPITAL LETTER A WITH MACRON
   574  		0x0100,
   575  		// Ll: LATIN SMALL LETTER A WITH MACRON
   576  		0x0101,
   577  		// Lt: LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
   578  		0x01C5,
   579  		// M: COMBINING GRAVE ACCENT
   580  		0x0300,
   581  		// Nd: ARABIC-INDIC DIGIT ZERO
   582  		0x0660,
   583  		// P: GREEK QUESTION MARK
   584  		0x037E,
   585  		// S: MODIFIER LETTER LEFT ARROWHEAD
   586  		0x02C2,
   587  		// Z: OGHAM SPACE MARK
   588  		0x1680,
   589  	}
   590  	for i := 0; i < uu.MaxLatin1+len(nonLatin1); i++ {
   591  		base := uint32(i)
   592  		if i >= uu.MaxLatin1 {
   593  			base = nonLatin1[i-uu.MaxLatin1]
   594  		}
   595  
   596  		// Note r is negative, but uint8(r) == uint8(base) and
   597  		// uint16(r) == uint16(base).
   598  		r := rune(base - 1<<31)
   599  		if uu.Is(uu.Letter, r) {
   600  			t.Errorf("Is(Letter, 0x%x - 1<<31) = true, want false", base)
   601  		}
   602  		if uu.IsControl(r) {
   603  			t.Errorf("IsControl(0x%x - 1<<31) = true, want false", base)
   604  		}
   605  		if uu.IsDigit(r) {
   606  			t.Errorf("IsDigit(0x%x - 1<<31) = true, want false", base)
   607  		}
   608  		if uu.IsGraphic(r) {
   609  			t.Errorf("IsGraphic(0x%x - 1<<31) = true, want false", base)
   610  		}
   611  		if uu.IsLetter(r) {
   612  			t.Errorf("IsLetter(0x%x - 1<<31) = true, want false", base)
   613  		}
   614  		if uu.IsLower(r) {
   615  			t.Errorf("IsLower(0x%x - 1<<31) = true, want false", base)
   616  		}
   617  		if uu.IsMark(r) {
   618  			t.Errorf("IsMark(0x%x - 1<<31) = true, want false", base)
   619  		}
   620  		if uu.IsNumber(r) {
   621  			t.Errorf("IsNumber(0x%x - 1<<31) = true, want false", base)
   622  		}
   623  		if uu.IsPrint(r) {
   624  			t.Errorf("IsPrint(0x%x - 1<<31) = true, want false", base)
   625  		}
   626  		if uu.IsPunct(r) {
   627  			t.Errorf("IsPunct(0x%x - 1<<31) = true, want false", base)
   628  		}
   629  		if uu.IsSpace(r) {
   630  			t.Errorf("IsSpace(0x%x - 1<<31) = true, want false", base)
   631  		}
   632  		if uu.IsSymbol(r) {
   633  			t.Errorf("IsSymbol(0x%x - 1<<31) = true, want false", base)
   634  		}
   635  		if uu.IsTitle(r) {
   636  			t.Errorf("IsTitle(0x%x - 1<<31) = true, want false", base)
   637  		}
   638  		if uu.IsUpper(r) {
   639  			t.Errorf("IsUpper(0x%x - 1<<31) = true, want false", base)
   640  		}
   641  	}
   642  }