github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/int_test.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package runtime
    16  
    17  import (
    18  	"math/big"
    19  	"runtime"
    20  	"testing"
    21  )
    22  
    23  func TestIntBinaryOps(t *testing.T) {
    24  	cases := []struct {
    25  		fun     binaryOpFunc
    26  		v, w    *Object
    27  		want    *Object
    28  		wantExc *BaseException
    29  	}{
    30  		{Add, NewInt(-100).ToObject(), NewInt(50).ToObject(), NewInt(-50).ToObject(), nil},
    31  		{Add, newObject(ObjectType), NewInt(-100).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for +: 'object' and 'int'")},
    32  		{Add, NewInt(MaxInt).ToObject(), NewInt(1).ToObject(), NewLong(new(big.Int).Add(maxIntBig, big.NewInt(1))).ToObject(), nil},
    33  		{And, NewInt(-100).ToObject(), NewInt(50).ToObject(), NewInt(16).ToObject(), nil},
    34  		{And, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(0).ToObject(), nil},
    35  		{And, newObject(ObjectType), NewInt(-100).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for &: 'object' and 'int'")},
    36  		{Div, NewInt(7).ToObject(), NewInt(3).ToObject(), NewInt(2).ToObject(), nil},
    37  		{Div, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), nil},
    38  		{Div, NewInt(MinInt).ToObject(), NewInt(MaxInt).ToObject(), NewInt(-2).ToObject(), nil},
    39  		{Div, NewList().ToObject(), NewInt(21).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for /: 'list' and 'int'")},
    40  		{Div, NewInt(1).ToObject(), NewInt(0).ToObject(), nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
    41  		{Div, NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), NewLong(new(big.Int).Neg(minIntBig)).ToObject(), nil},
    42  		{DivMod, NewInt(7).ToObject(), NewInt(3).ToObject(), NewTuple2(NewInt(2).ToObject(), NewInt(1).ToObject()).ToObject(), nil},
    43  		{DivMod, NewInt(3).ToObject(), NewInt(-7).ToObject(), NewTuple2(NewInt(-1).ToObject(), NewInt(-4).ToObject()).ToObject(), nil},
    44  		{DivMod, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewTuple2(NewInt(-1).ToObject(), NewInt(-1).ToObject()).ToObject(), nil},
    45  		{DivMod, NewInt(MinInt).ToObject(), NewInt(MaxInt).ToObject(), NewTuple2(NewInt(-2).ToObject(), NewInt(MaxInt-1).ToObject()).ToObject(), nil},
    46  		{DivMod, NewList().ToObject(), NewInt(21).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for divmod(): 'list' and 'int'")},
    47  		{DivMod, NewInt(1).ToObject(), NewInt(0).ToObject(), nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
    48  		{DivMod, NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), NewTuple2(NewLong(new(big.Int).Neg(minIntBig)).ToObject(), NewLong(big.NewInt(0)).ToObject()).ToObject(), nil},
    49  		{FloorDiv, NewInt(7).ToObject(), NewInt(3).ToObject(), NewInt(2).ToObject(), nil},
    50  		{FloorDiv, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), nil},
    51  		{FloorDiv, NewInt(MinInt).ToObject(), NewInt(MaxInt).ToObject(), NewInt(-2).ToObject(), nil},
    52  		{FloorDiv, NewList().ToObject(), NewInt(21).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for //: 'list' and 'int'")},
    53  		{FloorDiv, NewInt(1).ToObject(), NewInt(0).ToObject(), nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
    54  		{FloorDiv, NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), NewLong(new(big.Int).Neg(minIntBig)).ToObject(), nil},
    55  		{LShift, NewInt(2).ToObject(), NewInt(4).ToObject(), NewInt(32).ToObject(), nil},
    56  		{LShift, NewInt(-12).ToObject(), NewInt(10).ToObject(), NewInt(-12288).ToObject(), nil},
    57  		{LShift, NewInt(10).ToObject(), NewInt(100).ToObject(), NewLong(new(big.Int).Lsh(big.NewInt(10), 100)).ToObject(), nil},
    58  		{LShift, NewInt(2).ToObject(), NewInt(-5).ToObject(), nil, mustCreateException(ValueErrorType, "negative shift count")},
    59  		{LShift, NewInt(4).ToObject(), NewFloat(3.14).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for <<: 'int' and 'float'")},
    60  		{LShift, newObject(ObjectType), NewInt(4).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for <<: 'object' and 'int'")},
    61  		{RShift, NewInt(87).ToObject(), NewInt(3).ToObject(), NewInt(10).ToObject(), nil},
    62  		{RShift, NewInt(-101).ToObject(), NewInt(5).ToObject(), NewInt(-4).ToObject(), nil},
    63  		{RShift, NewInt(12).ToObject(), NewInt(10).ToObject(), NewInt(0).ToObject(), nil},
    64  		{RShift, NewInt(12).ToObject(), NewInt(-10).ToObject(), nil, mustCreateException(ValueErrorType, "negative shift count")},
    65  		{RShift, NewInt(4).ToObject(), NewFloat(3.14).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'int' and 'float'")},
    66  		{RShift, newObject(ObjectType), NewInt(4).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'object' and 'int'")},
    67  		{RShift, NewInt(4).ToObject(), newObject(ObjectType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for >>: 'int' and 'object'")},
    68  		{Mod, NewInt(3).ToObject(), NewInt(-7).ToObject(), NewInt(-4).ToObject(), nil},
    69  		{Mod, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), nil},
    70  		{Mod, NewInt(MinInt).ToObject(), NewInt(MaxInt).ToObject(), NewInt(MaxInt - 1).ToObject(), nil},
    71  		{Mod, None, NewInt(-4).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for %: 'NoneType' and 'int'")},
    72  		{Mod, NewInt(10).ToObject(), NewInt(0).ToObject(), nil, mustCreateException(ZeroDivisionErrorType, "integer division or modulo by zero")},
    73  		{Mod, NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), NewLong(big.NewInt(0)).ToObject(), nil},
    74  		{Mul, NewInt(-1).ToObject(), NewInt(-3).ToObject(), NewInt(3).ToObject(), nil},
    75  		{Mul, newObject(ObjectType), NewInt(101).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'object' and 'int'")},
    76  		{Mul, NewInt(MaxInt).ToObject(), NewInt(MaxInt - 1).ToObject(), NewLong(new(big.Int).Mul(big.NewInt(MaxInt), big.NewInt(MaxInt-1))).ToObject(), nil},
    77  		{Or, NewInt(-100).ToObject(), NewInt(50).ToObject(), NewInt(-66).ToObject(), nil},
    78  		{Or, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), nil},
    79  		{Or, newObject(ObjectType), NewInt(-100).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for |: 'object' and 'int'")},
    80  		{Pow, NewInt(2).ToObject(), NewInt(128).ToObject(), NewLong(big.NewInt(0).Exp(big.NewInt(2), big.NewInt(128), nil)).ToObject(), nil},
    81  		{Pow, NewInt(2).ToObject(), newObject(ObjectType), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for **: 'int' and 'object'")},
    82  		{Pow, NewInt(2).ToObject(), NewInt(-2).ToObject(), NewFloat(0.25).ToObject(), nil},
    83  		{Pow, newObject(ObjectType), NewInt(2).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for **: 'object' and 'int'")},
    84  		{Sub, NewInt(22).ToObject(), NewInt(18).ToObject(), NewInt(4).ToObject(), nil},
    85  		{Sub, IntType.ToObject(), NewInt(42).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for -: 'type' and 'int'")},
    86  		{Sub, NewInt(MinInt).ToObject(), NewInt(1).ToObject(), NewLong(new(big.Int).Sub(minIntBig, big.NewInt(1))).ToObject(), nil},
    87  		{Xor, NewInt(-100).ToObject(), NewInt(50).ToObject(), NewInt(-82).ToObject(), nil},
    88  		{Xor, NewInt(MaxInt).ToObject(), NewInt(MinInt).ToObject(), NewInt(-1).ToObject(), nil},
    89  		{Xor, newObject(ObjectType), NewInt(-100).ToObject(), nil, mustCreateException(TypeErrorType, "unsupported operand type(s) for ^: 'object' and 'int'")},
    90  	}
    91  	for _, cas := range cases {
    92  		testCase := invokeTestCase{args: wrapArgs(cas.v, cas.w), want: cas.want, wantExc: cas.wantExc}
    93  		if err := runInvokeTestCase(wrapFuncForTest(cas.fun), &testCase); err != "" {
    94  			t.Error(err)
    95  		}
    96  	}
    97  }
    98  
    99  func TestIntCompare(t *testing.T) {
   100  	cases := []invokeTestCase{
   101  		{args: wrapArgs(1, 1), want: compareAllResultEq},
   102  		{args: wrapArgs(309683958, 309683958), want: compareAllResultEq},
   103  		{args: wrapArgs(-306, 101), want: compareAllResultLT},
   104  		{args: wrapArgs(309683958, 101), want: compareAllResultGT},
   105  	}
   106  	for _, cas := range cases {
   107  		if err := runInvokeTestCase(compareAll, &cas); err != "" {
   108  			t.Error(err)
   109  		}
   110  	}
   111  }
   112  
   113  func TestIntInvert(t *testing.T) {
   114  	cases := []invokeTestCase{
   115  		{args: wrapArgs(2592), want: NewInt(-2593).ToObject()},
   116  		{args: wrapArgs(0), want: NewInt(-1).ToObject()},
   117  		{args: wrapArgs(-43), want: NewInt(42).ToObject()},
   118  		{args: wrapArgs(MaxInt), want: NewInt(MinInt).ToObject()},
   119  		{args: wrapArgs(MinInt), want: NewInt(MaxInt).ToObject()},
   120  	}
   121  	for _, cas := range cases {
   122  		if err := runInvokeMethodTestCase(IntType, "__invert__", &cas); err != "" {
   123  			t.Error(err)
   124  		}
   125  	}
   126  }
   127  
   128  func TestIntNew(t *testing.T) {
   129  	fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{
   130  		"__int__": newBuiltinFunction("__int__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   131  			return args[0], nil
   132  		}).ToObject(),
   133  	}))
   134  	strictEqType := newTestClassStrictEq("StrictEq", IntType)
   135  	subType := newTestClass("SubType", []*Type{IntType}, newStringDict(map[string]*Object{}))
   136  	subTypeObject := (&Int{Object: Object{typ: subType}, value: 3}).ToObject()
   137  	goodSlotType := newTestClass("GoodSlot", []*Type{ObjectType}, newStringDict(map[string]*Object{
   138  		"__int__": newBuiltinFunction("__int__", func(_ *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   139  			return NewInt(3).ToObject(), nil
   140  		}).ToObject(),
   141  	}))
   142  	badSlotType := newTestClass("BadSlot", []*Type{ObjectType}, newStringDict(map[string]*Object{
   143  		"__int__": newBuiltinFunction("__int__", func(_ *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   144  			return newObject(ObjectType), nil
   145  		}).ToObject(),
   146  	}))
   147  	slotSubTypeType := newTestClass("SlotSubType", []*Type{ObjectType}, newStringDict(map[string]*Object{
   148  		"__int__": newBuiltinFunction("__int__", func(_ *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   149  			return subTypeObject, nil
   150  		}).ToObject(),
   151  	}))
   152  	cases := []invokeTestCase{
   153  		{args: wrapArgs(IntType), want: NewInt(0).ToObject()},
   154  		{args: wrapArgs(IntType, "123"), want: NewInt(123).ToObject()},
   155  		{args: wrapArgs(IntType, " \t123"), want: NewInt(123).ToObject()},
   156  		{args: wrapArgs(IntType, "123 \t"), want: NewInt(123).ToObject()},
   157  		{args: wrapArgs(IntType, "FF", 16), want: NewInt(255).ToObject()},
   158  		{args: wrapArgs(IntType, "0xFF", 16), want: NewInt(255).ToObject()},
   159  		{args: wrapArgs(IntType, "0xE", 0), want: NewInt(14).ToObject()},
   160  		{args: wrapArgs(IntType, "0b101", 0), want: NewInt(5).ToObject()},
   161  		{args: wrapArgs(IntType, "0o726", 0), want: NewInt(470).ToObject()},
   162  		{args: wrapArgs(IntType, "0726", 0), want: NewInt(470).ToObject()},
   163  		{args: wrapArgs(IntType, "102", 0), want: NewInt(102).ToObject()},
   164  		{args: wrapArgs(IntType, 42), want: NewInt(42).ToObject()},
   165  		{args: wrapArgs(IntType, -3.14), want: NewInt(-3).ToObject()},
   166  		{args: wrapArgs(subType, overflowLong), wantExc: mustCreateException(OverflowErrorType, "Python int too large to convert to a Go int")},
   167  		{args: wrapArgs(strictEqType, 42), want: (&Int{Object{typ: strictEqType}, 42}).ToObject()},
   168  		{args: wrapArgs(IntType, newObject(goodSlotType)), want: NewInt(3).ToObject()},
   169  		{args: wrapArgs(IntType, newObject(badSlotType)), wantExc: mustCreateException(TypeErrorType, "__int__ returned non-int (type object)")},
   170  		{args: wrapArgs(IntType, newObject(slotSubTypeType)), want: subTypeObject},
   171  		{args: wrapArgs(strictEqType, newObject(goodSlotType)), want: (&Int{Object{typ: strictEqType}, 3}).ToObject()},
   172  		{args: wrapArgs(strictEqType, newObject(badSlotType)), wantExc: mustCreateException(TypeErrorType, "__int__ returned non-int (type object)")},
   173  		{args: wrapArgs(IntType, "0xff"), wantExc: mustCreateException(ValueErrorType, "invalid literal for int() with base 10: 0xff")},
   174  		{args: wrapArgs(IntType, ""), wantExc: mustCreateException(ValueErrorType, "invalid literal for int() with base 10: ")},
   175  		{args: wrapArgs(IntType, " "), wantExc: mustCreateException(ValueErrorType, "invalid literal for int() with base 10:  ")},
   176  		{args: wrapArgs(FloatType), wantExc: mustCreateException(TypeErrorType, "int.__new__(float): float is not a subtype of int")},
   177  		{args: wrapArgs(IntType, "asldkfj", 1), wantExc: mustCreateException(ValueErrorType, "int() base must be >= 2 and <= 36")},
   178  		{args: wrapArgs(IntType, "asldkfj", 37), wantExc: mustCreateException(ValueErrorType, "int() base must be >= 2 and <= 36")},
   179  		{args: wrapArgs(IntType, "@#%*(#", 36), wantExc: mustCreateException(ValueErrorType, "invalid literal for int() with base 36: @#%*(#")},
   180  		{args: wrapArgs(IntType, "123", overflowLong), wantExc: mustCreateException(OverflowErrorType, "Python int too large to convert to a Go int")},
   181  		{args: wrapArgs(IntType, "32059823095809238509238590835"), want: NewLong(func() *big.Int { i, _ := new(big.Int).SetString("32059823095809238509238590835", 0); return i }()).ToObject()},
   182  		{args: wrapArgs(IntType, newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, "int() argument must be a string or a number, not 'object'")},
   183  		{args: wrapArgs(IntType, newObject(fooType)), wantExc: mustCreateException(TypeErrorType, "__int__ returned non-int (type Foo)")},
   184  		{args: wrapArgs(IntType, 1, 2), wantExc: mustCreateException(TypeErrorType, "int() can't convert non-string with explicit base")},
   185  		{args: wrapArgs(IntType, 1, 2, 3), wantExc: mustCreateException(TypeErrorType, "int() takes at most 2 arguments (3 given)")},
   186  		{args: wrapArgs(IntType, "1", None), wantExc: mustCreateException(TypeErrorType, "an integer is required")},
   187  	}
   188  	for _, cas := range cases {
   189  		if err := runInvokeMethodTestCase(IntType, "__new__", &cas); err != "" {
   190  			t.Error(err)
   191  		}
   192  	}
   193  }
   194  
   195  func TestIntNewInterned(t *testing.T) {
   196  	// Make sure small integers are interned.
   197  	fun := wrapFuncForTest(func(f *Frame, i *Int) (bool, *BaseException) {
   198  		o, raised := IntType.Call(f, wrapArgs(i.Value()), nil)
   199  		if raised != nil {
   200  			return false, raised
   201  		}
   202  		return o == i.ToObject(), nil
   203  	})
   204  	cases := []invokeTestCase{
   205  		{args: wrapArgs(-1001), want: False.ToObject()},
   206  		{args: wrapArgs(0), want: True.ToObject()},
   207  		{args: wrapArgs(100), want: True.ToObject()},
   208  		{args: wrapArgs(120948298), want: False.ToObject()},
   209  	}
   210  	for _, cas := range cases {
   211  		if err := runInvokeTestCase(fun, &cas); err != "" {
   212  			t.Error(err)
   213  		}
   214  	}
   215  }
   216  
   217  func BenchmarkIntNew(b *testing.B) {
   218  	b.Run("interned", func(b *testing.B) {
   219  		var ret *Object
   220  		for i := 0; i < b.N; i++ {
   221  			ret = NewInt(1).ToObject()
   222  		}
   223  		runtime.KeepAlive(ret)
   224  	})
   225  
   226  	b.Run("not interned", func(b *testing.B) {
   227  		var ret *Object
   228  		for i := 0; i < b.N; i++ {
   229  			ret = NewInt(internedIntMax + 5).ToObject()
   230  		}
   231  		runtime.KeepAlive(ret)
   232  	})
   233  }
   234  
   235  func TestIntStrRepr(t *testing.T) {
   236  	cases := []invokeTestCase{
   237  		{args: wrapArgs(0), want: NewStr("0").ToObject()},
   238  		{args: wrapArgs(-303), want: NewStr("-303").ToObject()},
   239  		{args: wrapArgs(231095835), want: NewStr("231095835").ToObject()},
   240  	}
   241  	for _, cas := range cases {
   242  		if err := runInvokeTestCase(wrapFuncForTest(ToStr), &cas); err != "" {
   243  			t.Error(err)
   244  		}
   245  		if err := runInvokeTestCase(wrapFuncForTest(Repr), &cas); err != "" {
   246  			t.Error(err)
   247  		}
   248  	}
   249  }
   250  
   251  func TestIntCheckedAddMul(t *testing.T) {
   252  	cases := []struct {
   253  		f      func(a, b int) (int, bool)
   254  		a, b   int
   255  		want   int
   256  		wantOK bool
   257  	}{
   258  		{intCheckedAdd, 1, 2, 3, true},
   259  		{intCheckedAdd, MaxInt, -1, MaxInt - 1, true},
   260  		{intCheckedAdd, MaxInt, 0, MaxInt, true},
   261  		{intCheckedAdd, MaxInt, 1, 0, false},
   262  		{intCheckedAdd, MinInt, -1, 0, false},
   263  		{intCheckedAdd, MinInt, 0, MinInt, true},
   264  		{intCheckedAdd, MinInt, 1, MinInt + 1, true},
   265  		{intCheckedMul, MaxInt, 1, MaxInt, true},
   266  		{intCheckedMul, MaxInt, -1, MinInt + 1, true},
   267  		{intCheckedMul, MinInt, -1, 0, false},
   268  	}
   269  	for _, cas := range cases {
   270  		if got, gotOK := cas.f(cas.a, cas.b); got != cas.want || gotOK != cas.wantOK {
   271  			t.Errorf("%s(%v, %v) = (%v, %v), want (%v, %v)", getFuncName(cas.f), cas.a, cas.b, got, gotOK, cas.want, cas.wantOK)
   272  		}
   273  		if got, gotOK := cas.f(cas.b, cas.a); got != cas.want || gotOK != cas.wantOK {
   274  			t.Errorf("%s(%v, %v) = (%v, %v), want (%v, %v)", getFuncName(cas.f), cas.b, cas.a, got, gotOK, cas.want, cas.wantOK)
   275  		}
   276  	}
   277  }
   278  
   279  func TestIntCheckedDivMod(t *testing.T) {
   280  	cases := []struct {
   281  		f          func(a, b int) (int, divModResult)
   282  		a, b       int
   283  		want       int
   284  		wantResult divModResult
   285  	}{
   286  		{intCheckedDiv, 872, 736, 1, divModOK},
   287  		{intCheckedDiv, -320, 3, -107, divModOK},
   288  		{intCheckedDiv, 7, 3, 2, divModOK},
   289  		{intCheckedDiv, 7, -3, -3, divModOK},
   290  		{intCheckedDiv, -7, 3, -3, divModOK},
   291  		{intCheckedDiv, -7, -3, 2, divModOK},
   292  		{intCheckedDiv, 3, 7, 0, divModOK},
   293  		{intCheckedDiv, 3, -7, -1, divModOK},
   294  		{intCheckedDiv, -3, 7, -1, divModOK},
   295  		{intCheckedDiv, -3, -7, 0, divModOK},
   296  		{intCheckedDiv, MaxInt, MaxInt, 1, divModOK},
   297  		{intCheckedDiv, MaxInt, MinInt, -1, divModOK},
   298  		{intCheckedDiv, MinInt, MaxInt, -2, divModOK},
   299  		{intCheckedDiv, MinInt, MinInt, 1, divModOK},
   300  		{intCheckedDiv, 22, 0, 0, divModZeroDivision},
   301  		{intCheckedDiv, MinInt, -1, 0, divModOverflow},
   302  		{intCheckedMod, -142, -118, -24, divModOK},
   303  		{intCheckedMod, -225, 454, 229, divModOK},
   304  		{intCheckedMod, 7, 3, 1, divModOK},
   305  		{intCheckedMod, 7, -3, -2, divModOK},
   306  		{intCheckedMod, -7, 3, 2, divModOK},
   307  		{intCheckedMod, -7, -3, -1, divModOK},
   308  		{intCheckedMod, 3, 7, 3, divModOK},
   309  		{intCheckedMod, 3, -7, -4, divModOK},
   310  		{intCheckedMod, -3, 7, 4, divModOK},
   311  		{intCheckedMod, -3, -7, -3, divModOK},
   312  		{intCheckedMod, MaxInt, MaxInt, 0, divModOK},
   313  		{intCheckedMod, MaxInt, MinInt, -1, divModOK},
   314  		{intCheckedMod, MinInt, MaxInt, MaxInt - 1, divModOK},
   315  		{intCheckedMod, MinInt, MinInt, 0, divModOK},
   316  		{intCheckedMod, -50, 0, 0, divModZeroDivision},
   317  		{intCheckedMod, MinInt, -1, 0, divModOverflow},
   318  	}
   319  	for _, cas := range cases {
   320  		if got, gotResult := cas.f(cas.a, cas.b); got != cas.want || gotResult != cas.wantResult {
   321  			t.Errorf("%s(%v, %v) = (%v, %v), want (%v, %v)", getFuncName(cas.f), cas.a, cas.b, got, gotResult, cas.want, cas.wantResult)
   322  		}
   323  	}
   324  }
   325  
   326  func TestIntCheckedSub(t *testing.T) {
   327  	cases := []struct {
   328  		f      func(a, b int) (int, bool)
   329  		a, b   int
   330  		want   int
   331  		wantOK bool
   332  	}{
   333  		{intCheckedSub, MaxInt, MaxInt, 0, true},
   334  		{intCheckedSub, MaxInt, -1, 0, false},
   335  		{intCheckedSub, MaxInt, 0, MaxInt, true},
   336  		{intCheckedSub, MaxInt, 1, MaxInt - 1, true},
   337  		{intCheckedSub, MinInt, -1, MinInt + 1, true},
   338  		{intCheckedSub, MinInt, 0, MinInt, true},
   339  		{intCheckedSub, MinInt, 1, 0, false},
   340  		{intCheckedSub, MinInt, MinInt, 0, true},
   341  		{intCheckedSub, -2, MaxInt, 0, false},
   342  		{intCheckedSub, -1, MaxInt, MinInt, true},
   343  		{intCheckedSub, 0, MaxInt, MinInt + 1, true},
   344  		{intCheckedSub, -1, MinInt, MaxInt, true},
   345  		{intCheckedSub, 0, MinInt, 0, false},
   346  	}
   347  	for _, cas := range cases {
   348  		if got, gotOK := cas.f(cas.a, cas.b); got != cas.want || gotOK != cas.wantOK {
   349  			t.Errorf("%s(%v, %v) = (%v, %v), want (%v, %v)", getFuncName(cas.f), cas.a, cas.b, got, gotOK, cas.want, cas.wantOK)
   350  		}
   351  	}
   352  }