github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/math_test.go (about)

     1  // Copyright 2021 DataStax
     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 datacodec
    16  
    17  import (
    18  	"math"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  func Test_addExact(t *testing.T) {
    25  	tests := []struct {
    26  		name     string
    27  		x        int64
    28  		y        int64
    29  		expected int64
    30  		overflow bool
    31  	}{
    32  		{"zero", 0, 0, 0, false},
    33  		{"positive", 1, 1, 2, false},
    34  		{"negative", -1, -1, -2, false},
    35  
    36  		{"max + zero", math.MaxInt64, 0, math.MaxInt64, false},
    37  		{"zero + max", 0, math.MaxInt64, math.MaxInt64, false},
    38  		{"max-1 + 1", math.MaxInt64 - 1, 1, math.MaxInt64, false},
    39  		{"1 + max-1", 1, math.MaxInt64 - 1, math.MaxInt64, false},
    40  
    41  		{"max + 1", math.MaxInt64, 1, 0, true},
    42  		{"1 + max", 1, math.MaxInt64, 0, true},
    43  		{"max-1 + 2", math.MaxInt64 - 1, 2, 0, true},
    44  		{"2 + max-1", 2, math.MaxInt64 - 1, 0, true},
    45  
    46  		{"min + zero", math.MinInt64, 0, math.MinInt64, false},
    47  		{"zero + min", 0, math.MinInt64, math.MinInt64, false},
    48  		{"min+1 + -1", math.MinInt64 + 1, -1, math.MinInt64, false},
    49  		{"-1 + min+1", -1, math.MinInt64 + 1, math.MinInt64, false},
    50  
    51  		{"min - 1", math.MinInt64, -1, 0, true},
    52  		{"-1 + min", -1, math.MinInt64, 0, true},
    53  		{"min+1 + -2", math.MinInt64 + 1, -2, 0, true},
    54  		{"-2 + min+1", -2, math.MinInt64 + 1, 0, true},
    55  	}
    56  	for _, tt := range tests {
    57  		t.Run(tt.name, func(t *testing.T) {
    58  			actual, overflow := addExact(tt.x, tt.y)
    59  			assert.Equal(t, tt.expected, actual)
    60  			assert.Equal(t, tt.overflow, overflow)
    61  		})
    62  	}
    63  }
    64  
    65  func Test_multiplyExact(t *testing.T) {
    66  	tests := []struct {
    67  		name     string
    68  		x        int64
    69  		y        int64
    70  		expected int64
    71  		overflow bool
    72  	}{
    73  		{"0 * 0", 0, 0, 0, false},
    74  		{"1 * 0", 1, 0, 0, false},
    75  		{"0 * 1", 0, 1, 0, false},
    76  		{"1 * 1", 1, 1, 1, false},
    77  		{"-1 * -1", -1, -1, 1, false},
    78  		{"-1 * 1", -1, 1, -1, false},
    79  		{"1 * -1", 1, -1, -1, false},
    80  
    81  		{"max/2 * 2", math.MaxInt64 / 2, 2, math.MaxInt64 - 1, false},
    82  		{"2 * max/2", 2, math.MaxInt64 / 2, math.MaxInt64 - 1, false},
    83  		{"max/2+1 * 2", math.MaxInt64/2 + 1, 2, 0, true},
    84  		{"2 * max/2+1", 2, math.MaxInt64/2 + 1, 0, true},
    85  
    86  		{"max * 0", math.MaxInt64, 0, 0, false},
    87  		{"0 * max", 0, math.MaxInt64, 0, false},
    88  		{"max * 1", math.MaxInt64, 1, math.MaxInt64, false},
    89  		{"1 * max", 1, math.MaxInt64, math.MaxInt64, false},
    90  		{"max * -1", math.MaxInt64, -1, -math.MaxInt64, false},
    91  		{"-1 * max", -1, math.MaxInt64, -math.MaxInt64, false},
    92  		{"max * 2", math.MaxInt64, 2, 0, true},
    93  		{"2 * max", 2, math.MaxInt64, 0, true},
    94  		{"max * -2", math.MaxInt64, -2, 0, true},
    95  		{"-2 * max", -2, math.MaxInt64, 0, true},
    96  
    97  		{"min/2 * 2", math.MinInt64 / 2, 2, math.MinInt64, false},
    98  		{"2 * min/2", 2, math.MinInt64 / 2, math.MinInt64, false},
    99  		{"min/2-1 * 2", math.MinInt64/2 - 1, 2, 0, true},
   100  		{"2 * min/2-1", 2, math.MinInt64/2 - 1, 0, true},
   101  
   102  		{"min * 0", math.MinInt64, 0, 0, false},
   103  		{"0 * min", 0, math.MinInt64, 0, false},
   104  		{"min * 1", math.MinInt64, 1, math.MinInt64, false},
   105  		{"1 * min", 1, math.MinInt64, math.MinInt64, false},
   106  		{"min * -1", math.MinInt64, -1, 0, true},
   107  		{"-1 * min", -1, math.MinInt64, 0, true},
   108  		{"min * 2", math.MinInt64, 2, 0, true},
   109  		{"2 * min", 2, math.MinInt64, 0, true},
   110  		{"min * -2", math.MinInt64, -2, 0, true},
   111  		{"-2 * min", -2, math.MinInt64, 0, true},
   112  	}
   113  	for _, tt := range tests {
   114  		t.Run(tt.name, func(t *testing.T) {
   115  			actual, overflow := multiplyExact(tt.x, tt.y)
   116  			assert.Equal(t, tt.expected, actual)
   117  			assert.Equal(t, tt.overflow, overflow)
   118  		})
   119  	}
   120  }
   121  
   122  func Test_floorDiv(t *testing.T) {
   123  	tests := []struct {
   124  		name     string
   125  		x        int64
   126  		y        int64
   127  		expected int64
   128  	}{
   129  		{"0/1", 0, 1, 0},
   130  		{"0/-1", 0, -1, 0},
   131  		{"1/1", 1, 1, 1},
   132  		{"1/-1", 1, -1, -1},
   133  		{"2/2", 2, 2, 1},
   134  		{"2/-2", 2, -2, -1},
   135  		{"3/2", 3, 2, 1},
   136  		{"3/-2", 3, -2, -2},
   137  		{"-1/1", -1, 1, -1},
   138  		{"-1/-1", -1, -1, 1},
   139  		{"-2/2", -2, 2, -1},
   140  		{"-2/-2", -2, -2, 1},
   141  		{"-3/2", -3, 2, -2},
   142  		{"-3/-2", -3, -2, 1},
   143  
   144  		{"5/2", 5, 2, 2},
   145  		{"5/-2", 5, -2, -3},
   146  		{"-5/2", -5, 2, -3},
   147  		{"-5/-2", -5, -2, 2},
   148  
   149  		{"1/min", 1, math.MinInt64, -1},
   150  		{"-1/min", -1, math.MinInt64, 0},
   151  		{"1/max", 1, math.MaxInt64, 0},
   152  		{"-1/max", -1, math.MaxInt64, -1},
   153  
   154  		{"min/1", math.MinInt64, 1, math.MinInt64},
   155  		{"min/-1", math.MinInt64, -1, math.MinInt64}, // overflow: math.MaxInt64+1
   156  		{"max/1", math.MaxInt64, 1, math.MaxInt64},
   157  		{"max/-1", math.MaxInt64, -1, -math.MaxInt64},
   158  	}
   159  	for _, tt := range tests {
   160  		t.Run(tt.name, func(t *testing.T) {
   161  			actual := floorDiv(tt.x, tt.y)
   162  			assert.Equal(t, tt.expected, actual)
   163  		})
   164  	}
   165  }
   166  
   167  func Test_floorMod(t *testing.T) {
   168  	tests := []struct {
   169  		name     string
   170  		x        int64
   171  		y        int64
   172  		expected int64
   173  	}{
   174  		{"0/1", 0, 1, 0},
   175  		{"0/-1", 0, -1, 0},
   176  		{"1/1", 1, 1, 0},
   177  		{"1/-1", 1, -1, 0},
   178  		{"2/2", 2, 2, 0},
   179  		{"2/-2", 2, -2, 0},
   180  		{"3/2", 3, 2, 1},
   181  		{"3/-2", 3, -2, -1},
   182  		{"-1/1", -1, 1, 0},
   183  		{"-1/-1", -1, -1, 0},
   184  		{"-2/2", -2, 2, -0},
   185  		{"-2/-2", -2, -2, 0},
   186  		{"-3/2", -3, 2, 1},
   187  		{"-3/-2", -3, -2, -1},
   188  
   189  		{"5/2", 5, 2, 1},
   190  		{"5/-2", 5, -2, -1},
   191  		{"-5/2", -5, 2, 1},
   192  		{"-5/-2", -5, -2, -1},
   193  
   194  		{"1/min", 1, math.MinInt64, 1 + math.MinInt64}, // overflow
   195  		{"-1/min", -1, math.MinInt64, -1},
   196  		{"1/max", 1, math.MaxInt64, 1},
   197  		{"-1/max", -1, math.MaxInt64, -1 + math.MaxInt64},
   198  
   199  		{"min/1", math.MinInt64, 1, 0},
   200  		{"min/-1", math.MinInt64, -1, 0},
   201  		{"max/1", math.MaxInt64, 1, 0},
   202  		{"max/-1", math.MaxInt64, -1, 0},
   203  	}
   204  	for _, tt := range tests {
   205  		t.Run(tt.name, func(t *testing.T) {
   206  			actual := floorMod(tt.x, tt.y)
   207  			assert.Equal(t, tt.expected, actual)
   208  		})
   209  	}
   210  }