github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/tuple_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 grumpy
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  )
    21  
    22  func TestNewTuple(t *testing.T) {
    23  	cases := [][]*Object{
    24  		nil,
    25  		{newObject(ObjectType)},
    26  		{newObject(ObjectType), newObject(ObjectType)},
    27  	}
    28  	for _, args := range cases {
    29  		tuple := NewTuple(args...)
    30  		if !reflect.DeepEqual(tuple.elems, args) {
    31  			t.Errorf("NewTuple(%v) = %v, want %v", args, tuple.elems, args)
    32  		}
    33  	}
    34  }
    35  
    36  func TestTupleBinaryOps(t *testing.T) {
    37  	fun := wrapFuncForTest(func(f *Frame, fn binaryOpFunc, v, w *Object) (*Object, *BaseException) {
    38  		return fn(f, v, w)
    39  	})
    40  	cases := []invokeTestCase{
    41  		{args: wrapArgs(Add, newTestTuple(3), newTestTuple("foo")), want: newTestTuple(3, "foo").ToObject()},
    42  		{args: wrapArgs(Add, NewTuple(None), NewTuple()), want: NewTuple(None).ToObject()},
    43  		{args: wrapArgs(Add, NewTuple(), newObject(ObjectType)), wantExc: mustCreateException(TypeErrorType, "unsupported operand type(s) for +: 'tuple' and 'object'")},
    44  		{args: wrapArgs(Add, None, NewTuple()), wantExc: mustCreateException(TypeErrorType, "unsupported operand type(s) for +: 'NoneType' and 'tuple'")},
    45  		{args: wrapArgs(Mul, NewTuple(), 10), want: NewTuple().ToObject()},
    46  		{args: wrapArgs(Mul, newTestTuple("baz"), -2), want: NewTuple().ToObject()},
    47  		{args: wrapArgs(Mul, newTestTuple(None, None), 0), want: NewTuple().ToObject()},
    48  		{args: wrapArgs(Mul, newTestTuple(1, "bar"), 2), want: newTestTuple(1, "bar", 1, "bar").ToObject()},
    49  		{args: wrapArgs(Mul, 1, newTestTuple(1, "bar")), want: newTestTuple(1, "bar").ToObject()},
    50  		{args: wrapArgs(Mul, newObject(ObjectType), newTestTuple(newObject(ObjectType))), wantExc: mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'object' and 'tuple'")},
    51  		{args: wrapArgs(Mul, NewTuple(newObject(ObjectType)), NewTuple()), wantExc: mustCreateException(TypeErrorType, "unsupported operand type(s) for *: 'tuple' and 'tuple'")},
    52  		{args: wrapArgs(Mul, NewTuple(None, None), MaxInt), wantExc: mustCreateException(OverflowErrorType, "result too large")},
    53  	}
    54  	for _, cas := range cases {
    55  		if err := runInvokeTestCase(fun, &cas); err != "" {
    56  			t.Error(err)
    57  		}
    58  	}
    59  }
    60  
    61  func TestTupleCompare(t *testing.T) {
    62  	o := newObject(ObjectType)
    63  	cases := []invokeTestCase{
    64  		{args: wrapArgs(NewTuple(), NewTuple()), want: compareAllResultEq},
    65  		{args: wrapArgs(newTestTuple("foo", o), newTestTuple("foo", o)), want: compareAllResultEq},
    66  		{args: wrapArgs(newTestTuple(4), newTestTuple(3, 0)), want: compareAllResultGT},
    67  		{args: wrapArgs(newTestTuple(4), newTestTuple(4, 3, 0)), want: compareAllResultLT},
    68  		{args: wrapArgs(NewTuple(o), NewTuple()), want: compareAllResultGT},
    69  		{args: wrapArgs(NewTuple(o), newTestTuple("foo")), want: compareAllResultLT},
    70  	}
    71  	for _, cas := range cases {
    72  		if err := runInvokeTestCase(compareAll, &cas); err != "" {
    73  			t.Error(err)
    74  		}
    75  	}
    76  }
    77  
    78  func TestTupleCompareNotImplemented(t *testing.T) {
    79  	cas := invokeTestCase{args: wrapArgs(NewTuple(), 3), want: NotImplemented}
    80  	if err := runInvokeMethodTestCase(TupleType, "__eq__", &cas); err != "" {
    81  		t.Error(err)
    82  	}
    83  }
    84  
    85  func TestTupleContains(t *testing.T) {
    86  	cases := []invokeTestCase{
    87  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), 1), want: False.ToObject()},
    88  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), "foo"), want: True.ToObject()},
    89  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), 42), want: True.ToObject()},
    90  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), "bar"), want: True.ToObject()},
    91  		{args: wrapArgs(NewTuple(), newTestSlice(50, 100)), want: False.ToObject()},
    92  		{args: wrapArgs(newTestTuple(1, 2, 3, 4, 5), newTestSlice(1, None, 2)), want: False.ToObject()},
    93  		{args: wrapArgs(NewTuple(), 1), want: False.ToObject()},
    94  		{args: wrapArgs(newTestTuple(32), -100), want: False.ToObject()},
    95  		{args: wrapArgs(newTestTuple(1, 2, 3), newTestSlice(1, None, 0)), want: False.ToObject()},
    96  		{args: wrapArgs(newTestTuple(true), None), want: False.ToObject()},
    97  	}
    98  	for _, cas := range cases {
    99  		if err := runInvokeMethodTestCase(TupleType, "__contains__", &cas); err != "" {
   100  			t.Error(err)
   101  		}
   102  	}
   103  }
   104  
   105  func TestTupleCount(t *testing.T) {
   106  	cases := []invokeTestCase{
   107  		{args: wrapArgs(NewTuple(), NewInt(1)), want: NewInt(0).ToObject()},
   108  		{args: wrapArgs(NewTuple(None, None, None), None), want: NewInt(3).ToObject()},
   109  		{args: wrapArgs(NewTuple()), wantExc: mustCreateException(TypeErrorType, "'count' of 'tuple' requires 2 arguments")},
   110  	}
   111  	for _, cas := range cases {
   112  		if err := runInvokeMethodTestCase(TupleType, "count", &cas); err != "" {
   113  			t.Error(err)
   114  		}
   115  	}
   116  }
   117  
   118  func TestTupleIndex(t *testing.T) {
   119  	intIndexType := newTestClass("IntIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{
   120  		"__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
   121  			return NewInt(0).ToObject(), nil
   122  		}).ToObject(),
   123  	}))
   124  	cases := []invokeTestCase{
   125  		{args: wrapArgs(newTestTuple(), 1, "foo"), wantExc: mustCreateException(TypeErrorType, "slice indices must be integers or None or have an __index__ method")},
   126  		{args: wrapArgs(newTestTuple(10, 20, 30), 20), want: NewInt(1).ToObject()},
   127  		{args: wrapArgs(newTestTuple(10, 20, 30), 20, newObject(intIndexType)), want: NewInt(1).ToObject()},
   128  		{args: wrapArgs(newTestTuple(0, "foo", "bar"), "foo"), want: NewInt(1).ToObject()},
   129  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 3), want: NewInt(3).ToObject()},
   130  		{args: wrapArgs(newTestTuple(0, 2.0, 2, 3, 4, 2, 1, "foo"), 3, 3), want: NewInt(3).ToObject()},
   131  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 4), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   132  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 0, 4), want: NewInt(3).ToObject()},
   133  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 0, 3), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   134  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, -2), want: NewInt(3).ToObject()},
   135  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, -1), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   136  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 0, -1), want: NewInt(3).ToObject()},
   137  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 0, -2), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   138  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 0, 999), want: NewInt(3).ToObject()},
   139  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), "foo", 0, 999), wantExc: mustCreateException(ValueErrorType, "'foo' is not in tuple")},
   140  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 999), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   141  		{args: wrapArgs(newTestTuple(0, 1, 2, 3, 4), 3, 5, 0), wantExc: mustCreateException(ValueErrorType, "3 is not in tuple")},
   142  	}
   143  	for _, cas := range cases {
   144  		if err := runInvokeMethodTestCase(TupleType, "index", &cas); err != "" {
   145  			t.Error(err)
   146  		}
   147  	}
   148  }
   149  
   150  func BenchmarkTupleContains(b *testing.B) {
   151  	b.Run("false-3", func(b *testing.B) {
   152  		t := newTestTuple("foo", 42, "bar").ToObject()
   153  		a := wrapArgs(1)[0]
   154  		f := NewRootFrame()
   155  		b.ResetTimer()
   156  		for i := 0; i < b.N; i++ {
   157  			Contains(f, t, a)
   158  		}
   159  	})
   160  
   161  	b.Run("false-10", func(b *testing.B) {
   162  		t := newTestTuple("foo", 42, "bar", "foo", 42, "bar", "foo", 42, "bar", "baz").ToObject()
   163  		a := wrapArgs(1)[0]
   164  		f := NewRootFrame()
   165  		b.ResetTimer()
   166  		for i := 0; i < b.N; i++ {
   167  			Contains(f, t, a)
   168  		}
   169  	})
   170  
   171  	b.Run("true-3.1", func(b *testing.B) {
   172  		t := newTestTuple("foo", 42, "bar").ToObject()
   173  		a := wrapArgs("foo")[0]
   174  		f := NewRootFrame()
   175  		b.ResetTimer()
   176  		for i := 0; i < b.N; i++ {
   177  			Contains(f, t, a)
   178  		}
   179  	})
   180  
   181  	b.Run("true-3.3", func(b *testing.B) {
   182  		t := newTestTuple("foo", 42, "bar").ToObject()
   183  		a := wrapArgs("bar")[0]
   184  		f := NewRootFrame()
   185  		b.ResetTimer()
   186  		for i := 0; i < b.N; i++ {
   187  			Contains(f, t, a)
   188  		}
   189  	})
   190  
   191  	b.Run("true-10.10", func(b *testing.B) {
   192  		t := newTestTuple("foo", 42, "bar", "foo", 42, "bar", "foo", 42, "bar", "baz").ToObject()
   193  		a := wrapArgs("baz")[0]
   194  		f := NewRootFrame()
   195  		b.ResetTimer()
   196  		for i := 0; i < b.N; i++ {
   197  			Contains(f, t, a)
   198  		}
   199  	})
   200  }
   201  
   202  func TestTupleGetItem(t *testing.T) {
   203  	cases := []invokeTestCase{
   204  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), 1), want: NewInt(42).ToObject()},
   205  		{args: wrapArgs(newTestTuple("foo", 42, "bar"), -3), want: NewStr("foo").ToObject()},
   206  		{args: wrapArgs(NewTuple(), newTestSlice(50, 100)), want: NewTuple().ToObject()},
   207  		{args: wrapArgs(newTestTuple(1, 2, 3, 4, 5), newTestSlice(1, None, 2)), want: newTestTuple(2, 4).ToObject()},
   208  		{args: wrapArgs(NewTuple(), 1), wantExc: mustCreateException(IndexErrorType, "index out of range")},
   209  		{args: wrapArgs(newTestTuple(32), -100), wantExc: mustCreateException(IndexErrorType, "index out of range")},
   210  		{args: wrapArgs(newTestTuple(1, 2, 3), newTestSlice(1, None, 0)), wantExc: mustCreateException(ValueErrorType, "slice step cannot be zero")},
   211  		{args: wrapArgs(newTestTuple(true), None), wantExc: mustCreateException(TypeErrorType, "sequence indices must be integers, not NoneType")},
   212  	}
   213  	for _, cas := range cases {
   214  		if err := runInvokeMethodTestCase(TupleType, "__getitem__", &cas); err != "" {
   215  			t.Error(err)
   216  		}
   217  	}
   218  }
   219  
   220  func TestTupleLen(t *testing.T) {
   221  	tuple := newTestTuple("foo", 42, "bar")
   222  	if got := tuple.Len(); got != 3 {
   223  		t.Errorf("%v.Len() = %v, want 3", tuple, got)
   224  	}
   225  }
   226  
   227  func TestTupleNew(t *testing.T) {
   228  	cases := []invokeTestCase{
   229  		{want: NewTuple().ToObject()},
   230  		{args: wrapArgs(newTestTuple(1, 2, 3)), want: newTestTuple(1, 2, 3).ToObject()},
   231  		{args: wrapArgs(newTestDict(1, "foo", "bar", None)), want: newTestTuple(1, "bar").ToObject()},
   232  		{args: wrapArgs(42), wantExc: mustCreateException(TypeErrorType, "'int' object is not iterable")},
   233  	}
   234  	for _, cas := range cases {
   235  		if err := runInvokeTestCase(TupleType.ToObject(), &cas); err != "" {
   236  			t.Error(err)
   237  		}
   238  	}
   239  }
   240  
   241  func TestTupleStrRepr(t *testing.T) {
   242  	fun := wrapFuncForTest(func(f *Frame, o *Object) (*Tuple, *BaseException) {
   243  		str, raised := ToStr(f, o)
   244  		if raised != nil {
   245  			return nil, raised
   246  		}
   247  		repr, raised := Repr(f, o)
   248  		if raised != nil {
   249  			return nil, raised
   250  		}
   251  		return newTestTuple(str, repr), nil
   252  	})
   253  	cases := []invokeTestCase{
   254  		{args: wrapArgs(NewTuple()), want: newTestTuple("()", "()").ToObject()},
   255  		{args: wrapArgs(newTestTuple("foo")), want: newTestTuple("('foo',)", "('foo',)").ToObject()},
   256  		{args: wrapArgs(newTestTuple(TupleType, ExceptionType)), want: newTestTuple("(<type 'tuple'>, <type 'Exception'>)", "(<type 'tuple'>, <type 'Exception'>)").ToObject()},
   257  	}
   258  	for _, cas := range cases {
   259  		if err := runInvokeTestCase(fun, &cas); err != "" {
   260  			t.Error(err)
   261  		}
   262  	}
   263  }
   264  
   265  func TestTupleIter(t *testing.T) {
   266  	o := newObject(ObjectType)
   267  	cases := []invokeTestCase{
   268  		{args: wrapArgs(NewTuple()), want: NewList().ToObject()},
   269  		{args: wrapArgs(newTestTuple(1, o, "foo")), want: newTestList(1, o, "foo").ToObject()},
   270  	}
   271  	for _, cas := range cases {
   272  		if err := runInvokeTestCase(ListType.ToObject(), &cas); err != "" {
   273  			t.Error(err)
   274  		}
   275  	}
   276  }
   277  
   278  func newTestTuple(elems ...interface{}) *Tuple {
   279  	return NewTuple(wrapArgs(elems...)...)
   280  }