github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/bas/object_test.go (about)

     1  package bas
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"math"
     8  	"math/rand"
     9  	"runtime"
    10  	"runtime/debug"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/coyove/nj/internal"
    16  	"github.com/coyove/nj/typ"
    17  )
    18  
    19  func randString() string {
    20  	buf := make([]byte, 6)
    21  	rand.Read(buf)
    22  	return base64.StdEncoding.EncodeToString(buf)
    23  }
    24  
    25  func randInt(len, idx int) int {
    26  	buf := make([]byte, 6)
    27  	rand.Read(buf)
    28  	v := rand.Int()
    29  	if Int(v).HashCode()%uint32(len) == uint32(idx) {
    30  		return v
    31  	}
    32  	return randInt(len, idx)
    33  }
    34  
    35  func TestMapForeachDelete(t *testing.T) {
    36  	rand.Seed(time.Now().Unix())
    37  	check := func(o *Map, idx int, k int, dist int32) {
    38  		i := o.items[idx]
    39  		if i.key.Int() != k || i.dist != dist {
    40  			t.Fatal(o.items, string(debug.Stack()))
    41  		}
    42  	}
    43  
    44  	o := newMap(1)
    45  	o.noresize = true
    46  	a := randInt(2, 1)
    47  	b := randInt(2, 1)
    48  	c := randInt(2, 1)
    49  	o.Set(Int(a), Int(a)) // [null, a+0]
    50  	o.Set(Int(b), Int(b)) // [b+1, a+0]
    51  	o.Delete(Int(a))      // [b+1, deleted+0]
    52  	if o.items[0].dist != 1 || !o.items[1].pDeleted {
    53  		t.Fatal(o.items)
    54  	}
    55  	o.Set(Int(a), Int(a)) // [a+1, b+0]
    56  	check(o, 0, a, 1)
    57  	check(o, 1, b, 0)
    58  
    59  	o.Delete(Int(a))      // [deleted+1, b+0]
    60  	o.Set(Int(c), Int(c)) // [c+1, b+0]
    61  	check(o, 0, c, 1)
    62  	check(o, 1, b, 0)
    63  
    64  	o = newMap(2)
    65  	o.noresize = true
    66  	a = randInt(4, 1)
    67  	b = randInt(4, 1)
    68  	c = randInt(4, 1)
    69  	d := randInt(4, 1)
    70  	o.Set(Int(a), Int(a))
    71  	o.Set(Int(b), Int(b))
    72  	o.Set(Int(c), Int(c))
    73  	o.Set(Int(d), Int(d)) // [d+3, a+0, b+1, c+2]
    74  	check(o, 0, d, 3)
    75  	check(o, 1, a, 0)
    76  	check(o, 2, b, 1)
    77  	check(o, 3, c, 2)
    78  
    79  	o.Delete(Int(b))      // [d+3, a+0, deleted+1, c+2]
    80  	o.Set(Int(b), Int(b)) // [b+3, a+0, c+1, d+2]
    81  	check(o, 0, b, 3)
    82  	check(o, 1, a, 0)
    83  	check(o, 2, c, 1)
    84  	check(o, 3, d, 2)
    85  
    86  	o.Delete(Int(a))
    87  	o.Delete(Int(c)) // [b+3, deleted+0, deleted+1, d+2]
    88  	loopCount := 0
    89  	o.Foreach(func(k Value, v *Value) bool { loopCount++; return true })
    90  	if loopCount != 2 {
    91  		t.Fatal(loopCount, o.items)
    92  	}
    93  	for k, _ := o.FindNext(Nil); k != Nil; k, _ = o.FindNext(k) {
    94  		loopCount--
    95  	}
    96  	if loopCount != 0 {
    97  		t.Fatal(o.items)
    98  	}
    99  	a = randInt(4, 2)
   100  	o.Set(Int(a), Int(a)) // [a+2, deleted+0, d+1, b+2]
   101  	check(o, 0, a, 2)
   102  	check(o, 2, d, 1)
   103  	check(o, 3, b, 2)
   104  
   105  	if x, _ := o.Get(Int(a)); x.Int() != a {
   106  		t.Fatal(o.items)
   107  	}
   108  
   109  	o = newMap(4)
   110  	o.noresize = true
   111  	a = randInt(8, 1)
   112  	b = randInt(8, 1)
   113  	c = randInt(8, 1)
   114  	d = randInt(8, 2)
   115  	e := randInt(8, 4)
   116  	o.Set(Int(a), Int(a))
   117  	o.Set(Int(b), Int(b))
   118  	o.Set(Int(c), Int(c))
   119  	o.Set(Int(d), Int(d))
   120  	o.Set(Int(e), Int(e)) // [nil, a+0, b+1, c+2, d+2, e+1, nil, nil]
   121  	check(o, 1, a, 0)
   122  	check(o, 2, b, 1)
   123  	check(o, 3, c, 2)
   124  	check(o, 4, d, 2)
   125  	check(o, 5, e, 1)
   126  
   127  	o.Delete(Int(b))
   128  	o.Delete(Int(d)) // [nil, a+0, deleted+1, c+2, deleted+2, e+1, nil, nil]
   129  	if x, _ := o.Get(Int(b)); x != Nil {
   130  		t.Fatal(o.items)
   131  	}
   132  	if x, _ := o.Get(Int(c)); x != Int(c) {
   133  		t.Fatal(o.items)
   134  	}
   135  	o.Set(Int(d), Int(d)) // [nil, a+0, c+1, d+1, e+0, nil, nil, nil]
   136  	check(o, 1, a, 0)
   137  	check(o, 2, c, 1)
   138  	check(o, 3, d, 1)
   139  	check(o, 4, e, 0)
   140  
   141  	o.Delete(Int(e))
   142  	o.Set(Int(e), Int(e))
   143  	check(o, 1, a, 0)
   144  	check(o, 2, c, 1)
   145  	check(o, 3, d, 1)
   146  	check(o, 4, e, 0)
   147  }
   148  
   149  func BenchmarkRHMap10(b *testing.B)      { benchmarkRHMap(b, 10) }
   150  func BenchmarkGoMap10(b *testing.B)      { benchmarkGoMap(b, 10) }
   151  func BenchmarkRHMap20(b *testing.B)      { benchmarkRHMap(b, 20) }
   152  func BenchmarkGoMap20(b *testing.B)      { benchmarkGoMap(b, 20) }
   153  func BenchmarkRHMap50(b *testing.B)      { benchmarkRHMap(b, 50) }
   154  func BenchmarkGoMap50(b *testing.B)      { benchmarkGoMap(b, 50) }
   155  func BenchmarkRHMap5000(b *testing.B)    { benchmarkRHMap(b, 5000) }
   156  func BenchmarkGoMap5000(b *testing.B)    { benchmarkGoMap(b, 5000) }
   157  func BenchmarkRHMapUnc10(b *testing.B)   { benchmarkRHMapUnconstrainted(b, 10) }
   158  func BenchmarkGoMapUnc10(b *testing.B)   { benchmarkGoMapUnconstrainted(b, 10) }
   159  func BenchmarkRHMapUnc1000(b *testing.B) { benchmarkRHMapUnconstrainted(b, 1000) }
   160  func BenchmarkGoMapUnc1000(b *testing.B) { benchmarkGoMapUnconstrainted(b, 1000) }
   161  
   162  func benchmarkRHMap(b *testing.B, n int) {
   163  	rand.Seed(time.Now().Unix())
   164  	m := newMap(n)
   165  	for i := 0; i < n; i++ {
   166  		m.Set(Int64(int64(i)), Int64(int64(i)))
   167  	}
   168  	for i := 0; i < b.N; i++ {
   169  		idx := rand.Intn(n)
   170  		if x, _ := m.Get(Int64(int64(idx))); x != Int64(int64(idx)) {
   171  			b.Fatal(idx, m)
   172  		}
   173  	}
   174  }
   175  
   176  func benchmarkRHMapUnconstrainted(b *testing.B, n int) {
   177  	rand.Seed(time.Now().Unix())
   178  	m := newMap(1)
   179  	for i := 0; i < b.N; i++ {
   180  		for i := 0; i < n; i++ {
   181  			x := rand.Intn(n)
   182  			m.Set(Int64(int64(x)), Int64(int64(i)))
   183  		}
   184  	}
   185  }
   186  
   187  func benchmarkGoMap(b *testing.B, n int) {
   188  	rand.Seed(time.Now().Unix())
   189  	m := map[int]int{}
   190  	for i := 0; i < n; i++ {
   191  		m[i] = i
   192  	}
   193  	for i := 0; i < b.N; i++ {
   194  		idx := rand.Intn(n)
   195  		if m[idx] == -1 {
   196  			b.Fatal(idx, m)
   197  		}
   198  	}
   199  }
   200  
   201  func benchmarkGoMapUnconstrainted(b *testing.B, n int) {
   202  	rand.Seed(time.Now().Unix())
   203  	m := map[int]int{}
   204  	for i := 0; i < b.N; i++ {
   205  		for i := 0; i < n; i++ {
   206  			idx := rand.Intn(n)
   207  			m[idx] = i
   208  		}
   209  	}
   210  }
   211  
   212  func TestRHMap(t *testing.T) {
   213  	rand.Seed(time.Now().Unix())
   214  	m := newMap(0)
   215  	m2 := map[int64]int64{}
   216  	counter := int64(0)
   217  	for i := 0; i < 1e6; i++ {
   218  		x := rand.Int63()
   219  		if x%2 == 0 {
   220  			x = counter
   221  			counter++
   222  		}
   223  		m.Set(Int64(x), Int64(x))
   224  		m2[x] = x
   225  	}
   226  	for k := range m2 {
   227  		delete(m2, k)
   228  		m.Delete(Int64(k))
   229  		if rand.Intn(10000) == 0 {
   230  			break
   231  		}
   232  	}
   233  
   234  	fmt.Println(m.Len(), m.Cap(), len(m2))
   235  
   236  	for k, v := range m2 {
   237  		if x, _ := m.Get(Int64(k)); x.Int64() != v {
   238  			m.Foreach(func(mk Value, mv *Value) bool {
   239  				if mk.Int64() == k {
   240  					t.Log(mk, *mv)
   241  				}
   242  				return true
   243  			})
   244  			t.Fatal(x, k, v)
   245  		}
   246  	}
   247  
   248  	if m.Len() != len(m2) {
   249  		t.Fatal(m.Len(), len(m2))
   250  	}
   251  
   252  	for k, v := m.FindNext(Nil); k != Nil; k, v = m.FindNext(k) {
   253  		if _, ok := m2[k.Int64()]; !ok {
   254  			t.Fatal(k, v, len(m2))
   255  		}
   256  		delete(m2, k.Int64())
   257  	}
   258  	if len(m2) != 0 {
   259  		t.Fatal(len(m2))
   260  	}
   261  
   262  	m.Clear()
   263  	m.Set(Int64(0), Int64(0))
   264  	m.Set(Int64(1), Int64(1))
   265  	m.Set(Int64(2), Int64(2))
   266  
   267  	for i := 4; i < 9; i++ {
   268  		m.Set(Int64(int64(i*i)), Int64(0))
   269  	}
   270  
   271  	for k, v := m.FindNext(Nil); k != Nil; k, v = m.FindNext(k) {
   272  		fmt.Println(k, v)
   273  	}
   274  }
   275  
   276  func TestMapDistance(t *testing.T) {
   277  	test := func(sz int) {
   278  		o := newMap(sz)
   279  		for i := 0; i < sz; i++ {
   280  			o.Set(Int(randInt(sz, i)), Int(i))
   281  		}
   282  		for _, i := range o.items {
   283  			if i.key != Nil {
   284  				if i.dist != 0 {
   285  					t.Fatal(o.items)
   286  				}
   287  			}
   288  		}
   289  	}
   290  	for i := 1; i < 16; i++ {
   291  		test(i)
   292  	}
   293  	test = func(sz int) {
   294  		o := newMap(sz / 2)
   295  		o.noresize = true
   296  		for i := 0; i < sz; i++ {
   297  			o.Set(Int(randInt(sz, i)), Int(i))
   298  		}
   299  		for _, i := range o.items {
   300  			if i.dist != 0 {
   301  				t.Fatal(o.items)
   302  			}
   303  		}
   304  	}
   305  	for i := 2; i <= 16; i += 2 {
   306  		test(i)
   307  	}
   308  }
   309  
   310  func TestHashcodeDist(t *testing.T) {
   311  	rand.Seed(time.Now().Unix())
   312  	for _, a := range []string{"a", "b", "c", "z", randString(), randString(), randString(), randString()} {
   313  		fmt.Println(Str(a).HashCode() % 32)
   314  	}
   315  
   316  	z := map[uint32]int{}
   317  	m := newMap(0)
   318  	rand.Seed(time.Now().Unix())
   319  	for i := 0; i < 1e6; i++ {
   320  		v := Int64(int64(i)).HashCode() % 32
   321  		z[v]++
   322  		m.Set(Int(i), Int(i))
   323  	}
   324  	fmt.Println(z, m.density(), m.Cap())
   325  
   326  	z = map[uint32]int{}
   327  	for i := 0; i < 1e6; i++ {
   328  		v := Int64(rand.Int63()).HashCode() % 32
   329  		z[v]++
   330  	}
   331  	fmt.Println((z))
   332  
   333  	z = map[uint32]int{}
   334  	for i := 0; i < 1e6; i++ {
   335  		v := Str(randString()).HashCode() % 32
   336  		z[v]++
   337  	}
   338  	fmt.Println((z))
   339  
   340  	z = map[uint32]int{}
   341  	m.Clear()
   342  	for i := 0; i < 1e6; i++ {
   343  		x := fmt.Sprintf("%016x", rand.Uint64())
   344  		v := Str(x).HashCode() % 32
   345  		z[v]++
   346  		m.Set(Str(x), Str(x))
   347  	}
   348  	fmt.Println(z, m.density(), m.Cap())
   349  
   350  	m = newMap(0)
   351  	for i := 0; i < 20; i++ {
   352  		m.Set(Int(i), Int(i))
   353  	}
   354  	fmt.Println(m.DebugString())
   355  }
   356  
   357  func BenchmarkStr(b *testing.B) {
   358  	for i := 0; i < b.N; i++ {
   359  		Str("\x00")
   360  	}
   361  }
   362  
   363  func BenchmarkStrHashCode(b *testing.B) {
   364  	x := Str(randString() + randString())
   365  	for i := 0; i < b.N; i++ {
   366  		x.HashCode()
   367  	}
   368  }
   369  
   370  func BenchmarkContains(b *testing.B) {
   371  	m := newMap(0)
   372  	k2 := []Value{}
   373  	for i := 0; i < 1e3; i++ {
   374  		k := randString()
   375  		m.Set(Str(k), Int(0))
   376  		k2 = append(k2, Str(randString()))
   377  	}
   378  	for i := 0; i < b.N; i++ {
   379  		if m.Contains(k2[rand.Intn(len(k2))]) {
   380  			b.Fatal()
   381  		}
   382  	}
   383  }
   384  
   385  func BenchmarkContainsNative(b *testing.B) {
   386  	k2 := []string{}
   387  	m := map[string]bool{}
   388  	for i := 0; i < 1e3; i++ {
   389  		k := randString()
   390  		m[k] = true
   391  		k2 = append(k2, randString())
   392  	}
   393  	for i := 0; i < b.N; i++ {
   394  		if m[k2[rand.Intn(len(k2))]] {
   395  			b.Fatal()
   396  		}
   397  	}
   398  }
   399  
   400  func TestFalsyValue(t *testing.T) {
   401  	assert := func(b bool) {
   402  		if !b {
   403  			_, fn, ln, _ := runtime.Caller(1)
   404  			t.Fatal(fn, ln)
   405  		}
   406  	}
   407  
   408  	assert(Float64(0).IsFalse())
   409  	assert(Float64(1 / math.Inf(-1)).IsFalse())
   410  	assert(!Float64(math.NaN()).IsFalse())
   411  	assert(!Bool(true).IsFalse())
   412  	assert(Bool(false).IsFalse())
   413  	assert(Str("").IsFalse())
   414  	assert(Str("\x00").IsTrue())
   415  	assert(Str("\x00\x00").IsTrue())
   416  	assert(Str("\x00\x00\x00").IsTrue())
   417  	assert(Str("\x00\x00\x00\x00").IsTrue())
   418  	assert(Str("\x00\x00\x00\x00\x00").IsTrue())
   419  	assert(Str(strings.Repeat("\x00", 6)).IsTrue())
   420  	assert(Str(strings.Repeat("\x00", 7)).IsTrue())
   421  	assert(Str(strings.Repeat("\x00", 8)).IsTrue())
   422  	assert(Byte('a') == Str("a"))
   423  	assert(Rune('a') == Str("a"))
   424  	assert(Rune('\u263a') == Str("\u263a"))
   425  	assert(Rune('\U0001f60a') == Str("\U0001f60a"))
   426  	assert(Bytes(nil).IsTrue())
   427  	assert(Bytes([]byte("")).IsTrue())
   428  	assert(!ValueOf([]byte("")).IsFalse())
   429  	assert(Str("\x00\x00\x00\x00\x00\x00\x00").Less(Str("\x00\x00\x00\x00\x00\x00\x00\x00")))
   430  	assert(newArray().ToValue().IsArray())
   431  }
   432  
   433  func TestFormat(t *testing.T) {
   434  	sprintf := func(format string, args ...interface{}) string {
   435  		p := &bytes.Buffer{}
   436  		internal.Fprintf(p, format, args...)
   437  		return p.String()
   438  	}
   439  
   440  	type payload struct {
   441  		f   string
   442  		v   interface{}
   443  		res string
   444  	}
   445  
   446  	payloads := []payload{
   447  		{"%d", uint(12345), "12345"},
   448  		{"%d", int(-12345), "-12345"},
   449  		{"%d", ^uint8(0), "255"},
   450  		{"%d", ^uint16(0), "65535"},
   451  		{"%d", ^uint32(0), "4294967295"},
   452  		{"%d", ^uint64(0), "18446744073709551615"},
   453  		{"%d", int8(-1 << 7), "-128"},
   454  		{"%d", int16(-1 << 15), "-32768"},
   455  		{"%d", int32(-1 << 31), "-2147483648"},
   456  		{"%d", int64(-1 << 63), "-9223372036854775808"},
   457  		{"%.d", 0, ""},
   458  		{"%.0d", 0, ""},
   459  		{"%6.0d", 0, "      "},
   460  		{"%06.0d", 0, "      "},
   461  		{"% d", 12345, " 12345"},
   462  		{"%+d", 12345, "+12345"},
   463  		{"%+d", -12345, "-12345"},
   464  		{"%b", 7, "111"},
   465  		{"%b", -6, "-110"},
   466  		{"%#b", 7, "0b111"},
   467  		{"%#b", -6, "-0b110"},
   468  		{"%b", ^uint32(0), "11111111111111111111111111111111"},
   469  		{"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"},
   470  		{"%o", 01234, "1234"},
   471  		{"%o", -01234, "-1234"},
   472  		{"%#o", 01234, "01234"},
   473  		{"%#o", -01234, "-01234"},
   474  		{"%O", 01234, "0o1234"},
   475  		{"%O", -01234, "-0o1234"},
   476  		{"%o", ^uint32(0), "37777777777"},
   477  		{"%o", ^uint64(0), "1777777777777777777777"},
   478  		{"%#X", 0, "0X0"},
   479  		{"%x", 0x12abcdef, "12abcdef"},
   480  		{"%X", 0x12abcdef, "12ABCDEF"},
   481  		{"%x", ^uint32(0), "ffffffff"},
   482  		{"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"},
   483  		{"%.20b", 7, "00000000000000000111"},
   484  		{"%10d", 12345, "     12345"},
   485  		{"%10d", -12345, "    -12345"},
   486  		{"%+10d", 12345, "    +12345"},
   487  		{"%010d", 12345, "0000012345"},
   488  		{"%010d", -12345, "-000012345"},
   489  		{"%20.8d", 1234, "            00001234"},
   490  		{"%20.8d", -1234, "           -00001234"},
   491  		{"%020.8d", 1234, "            00001234"},
   492  		{"%020.8d", -1234, "           -00001234"},
   493  		{"%-20.8d", 1234, "00001234            "},
   494  		{"%-20.8d", -1234, "-00001234           "},
   495  		{"%-#20.8x", 0x1234abc, "0x01234abc          "},
   496  		{"%-#20.8X", 0x1234abc, "0X01234ABC          "},
   497  		{"%-#20.8o", 01234, "00001234            "},
   498  		{"%+.3e", 0.0, "+0.000e+00"},
   499  		{"%+.3e", 1.0, "+1.000e+00"},
   500  		{"%+.3x", 0.0, "+0x0.000p+00"},
   501  		{"%+.3x", 1.0, "+0x1.000p+00"},
   502  		{"%+.3f", -1.0, "-1.000"},
   503  		{"%+.3F", -1.0, "-1.000"},
   504  		{"%+.3F", float32(-1.0), "-1.000"},
   505  		{"%+07.2f", 1.0, "+001.00"},
   506  		{"%+07.2f", -1.0, "-001.00"},
   507  		{"%-07.2f", 1.0, "1.00   "},
   508  		{"%-07.2f", -1.0, "-1.00  "},
   509  		{"%+-07.2f", 1.0, "+1.00  "},
   510  		{"%+-07.2f", -1.0, "-1.00  "},
   511  		{"%-+07.2f", 1.0, "+1.00  "},
   512  		{"%-+07.2f", -1.0, "-1.00  "},
   513  		{"%+10.2f", +1.0, "     +1.00"},
   514  		{"%+10.2f", -1.0, "     -1.00"},
   515  		{"% .3E", -1.0, "-1.000E+00"},
   516  		{"% .3e", 1.0, " 1.000e+00"},
   517  		{"% .3X", -1.0, "-0X1.000P+00"},
   518  		{"% .3x", 1.0, " 0x1.000p+00"},
   519  		{"%+.3g", 0.0, "+0"},
   520  		{"%+.3g", 1.0, "+1"},
   521  		{"%+.3g", -1.0, "-1"},
   522  		{"% .3g", -1.0, "-1"},
   523  		{"% .3g", 1.0, " 1"},
   524  		{"%b", float32(1.0), "8388608p-23"},
   525  		{"%b", 1.0, "4503599627370496p-52"},
   526  		// Test sharp flag used with floats.
   527  		{"%#g", 1e-323, "1.00000e-323"},
   528  		{"%#g", -1.0, "-1.00000"},
   529  		{"%#g", 1.1, "1.10000"},
   530  		{"%#g", 123456.0, "123456."},
   531  		{"%#g", 1234567.0, "1.234567e+06"},
   532  		{"%#g", 1230000.0, "1.23000e+06"},
   533  		{"%#g", 1000000.0, "1.00000e+06"},
   534  		{"%#.0f", 1.0, "1."},
   535  		{"%#.0e", 1.0, "1.e+00"},
   536  		{"%#.0x", 1.0, "0x1.p+00"},
   537  		{"%#.0g", 1.0, "1."},
   538  		{"%#.0g", 1100000.0, "1.e+06"},
   539  		{"%#.4f", 1.0, "1.0000"},
   540  		{"%#.4e", 1.0, "1.0000e+00"},
   541  		{"%#.4x", 1.0, "0x1.0000p+00"},
   542  		{"%#.4g", 1.0, "1.000"},
   543  		{"%#.4g", 100000.0, "1.000e+05"},
   544  		{"%#.4g", 1.234, "1.234"},
   545  		{"%#.4g", 0.1234, "0.1234"},
   546  		{"%#.4g", 1.23, "1.230"},
   547  		{"%#.4g", 0.123, "0.1230"},
   548  		{"%#.4g", 1.2, "1.200"},
   549  		{"%#.4g", 0.12, "0.1200"},
   550  		{"%#.4g", 10.2, "10.20"},
   551  		{"%#.4g", 0.0, "0.000"},
   552  		{"%#.4g", 0.012, "0.01200"},
   553  		{"%#.0f", 123.0, "123."},
   554  		{"%#.0e", 123.0, "1.e+02"},
   555  		{"%#.0x", 123.0, "0x1.p+07"},
   556  		{"%#.0g", 123.0, "1.e+02"},
   557  		{"%#.4f", 123.0, "123.0000"},
   558  		{"%#.4e", 123.0, "1.2300e+02"},
   559  		{"%#.4x", 123.0, "0x1.ec00p+06"},
   560  		{"%#.4g", 123.0, "123.0"},
   561  		{"%#.4g", 123000.0, "1.230e+05"},
   562  		{"%#9.4g", 1.0, "    1.000"},
   563  		// The sharp flag has no effect for binary float format.
   564  		{"%#b", 1.0, "4503599627370496p-52"},
   565  		// Precision has no effect for binary float format.
   566  		{"%.4b", float32(1.0), "8388608p-23"},
   567  		{"%.4b", -1.0, "-4503599627370496p-52"},
   568  		// Test correct f.intbuf boundary checks.
   569  		// float infinites and NaNs
   570  		{"%f", math.Inf(1), "+Inf"},
   571  		{"%.1f", math.Inf(-1), "-Inf"},
   572  		{"% f", math.NaN(), " NaN"},
   573  		{"%20f", math.Inf(1), "                +Inf"},
   574  		{"% 20F", math.Inf(1), "                 Inf"},
   575  		{"% 20e", math.Inf(-1), "                -Inf"},
   576  		{"% 20x", math.Inf(-1), "                -Inf"},
   577  		{"%+20E", math.Inf(-1), "                -Inf"},
   578  		{"%+20X", math.Inf(-1), "                -Inf"},
   579  		{"% +20g", math.Inf(-1), "                -Inf"},
   580  		{"%+-20G", math.Inf(1), "+Inf                "},
   581  		{"%20e", math.NaN(), "                 NaN"},
   582  		{"%20x", math.NaN(), "                 NaN"},
   583  		{"% +20E", math.NaN(), "                +NaN"},
   584  		{"% +20X", math.NaN(), "                +NaN"},
   585  		{"% -20g", math.NaN(), " NaN                "},
   586  		{"%+-20G", math.NaN(), "+NaN                "},
   587  		// Zero padding does not apply to infinities and NaN.
   588  		{"%+020e", math.Inf(1), "                +Inf"},
   589  		{"%+020x", math.Inf(1), "                +Inf"},
   590  		{"%-020f", math.Inf(-1), "-Inf                "},
   591  		{"%-020E", math.NaN(), "NaN                 "},
   592  		{"%-020X", math.NaN(), "NaN                 "},
   593  	}
   594  
   595  	for _, p := range payloads {
   596  		if v := sprintf(p.f, p.v); v != p.res {
   597  			t.Fatal(p.f, p.v, "->", v, p.res)
   598  		}
   599  	}
   600  }
   601  
   602  func TestShape(t *testing.T) {
   603  	assertError := func(f bool, err error) {
   604  		if (err == nil) == f {
   605  			t.Fatal(err, string(debug.Stack()))
   606  		}
   607  	}
   608  
   609  	NewShape("")
   610  	// Shape(",")
   611  	// Shape("[")
   612  	// Shape("]")
   613  	// Shape("[,]")
   614  
   615  	assertError(false, NewShape("i")(Int(1)))
   616  	assertError(false, NewShape("n")(Int(1)))
   617  	assertError(false, NewShape("n")(Float64(1)))
   618  	assertError(false, NewShape("(i)")(Array(Int(1))))
   619  	assertError(false, NewShape("(i i)")(Array(Int(1), Int(2))))
   620  	assertError(false, NewShape("[i i]")(Array(Int(1), Int(2))))
   621  	assertError(false, NewShape("[i i]")(Array(Int(1), Int(2), Int(3), Int(4))))
   622  	assertError(false, NewShape("[i,i]")(Array()))
   623  	assertError(false, NewShape("(i,is)")(Array(Int(1), Int(2))))
   624  	assertError(false, NewShape("(i,is)")(Array(Int(1), Str("2"))))
   625  	assertError(false, NewShape("([] is)")(Array(Array(Int(1)), Str("2"))))
   626  	assertError(false, NewShape("([@*int] is)")(Array(Array(NewNative(new(int)).ToValue()), Str("2"))))
   627  	assertError(false, NewShape("E")(Error(nil, fmt.Errorf("test"))))
   628  	assertError(false, NewShape("@error")(Error(nil, fmt.Errorf("test"))))
   629  	assertError(true, NewShape("[i]")(Array(Int(1), Float64(0.5))))
   630  	assertError(false, NewShape("{} ")(NewObject(0).ToValue()))
   631  
   632  	o := NewObject(10)
   633  	o.Set(Int(1), Array())
   634  	o.Set(Int(2), Array())
   635  	assertError(false, NewShape("({i:[]} is)")(Array(o.ToValue(), Str("2"))))
   636  
   637  	o.Clear()
   638  	o.Set(Int(1), True)
   639  	o.Set(Int(2), Str(""))
   640  	assertError(false, NewShape("{}")(o.ToValue()))
   641  	assertError(false, NewShape("{i}")(o.ToValue()))
   642  	assertError(false, NewShape("{i v}")(o.ToValue()))
   643  
   644  	o.Clear()
   645  	assertError(false, NewShape("{i}")(o.ToValue()))
   646  	assertError(false, NewShape("<i,{}>")(o.ToValue()))
   647  	assertError(false, NewShape("<i,@object>")(o.ToValue()))
   648  
   649  	p := NewNamedObject("test", 0)
   650  	assertError(true, NewShape("@test")(o.ToValue()))
   651  	o.SetPrototype(p)
   652  	assertError(false, NewShape("@test")(o.ToValue()))
   653  	assertError(false, NewShape("@object")(o.ToValue()))
   654  
   655  	assertError(false, NewShape("R")(ValueOf(&bytes.Buffer{})))
   656  	assertError(true, NewShape("C")(ValueOf(&bytes.Buffer{})))
   657  
   658  	assertError(false, NewShape("<[],{}>")(o.ToValue()))
   659  }
   660  
   661  func BenchmarkShape(b *testing.B) {
   662  	v := Array(Int(1), Int(2))
   663  	s := NewShape("[i,i]")
   664  	for i := 0; i < b.N; i++ {
   665  		s(v)
   666  	}
   667  }
   668  
   669  func BenchmarkShapeSimple(b *testing.B) {
   670  	v := Int(1)
   671  	for i := 0; i < b.N; i++ {
   672  		v.AssertShape("si", "")
   673  	}
   674  }
   675  
   676  func BenchmarkShapeType(b *testing.B) {
   677  	v := Int(1)
   678  	for i := 0; i < b.N; i++ {
   679  		switch v.Type() {
   680  		case typ.Number, typ.String:
   681  			v.AssertNumber("")
   682  		}
   683  	}
   684  }