Repository: maypok86/otter (go)

Issue:
[BUG] The checkedAdd method will not return maxInt64 in case of overflow
## Description

The [checkedAdd](https://github.com/maypok86/otter/blob/e57f61b947ff2308dd2e02ee181cef634b8dfd66/stats.go#L83) will return (maxInt64 - 2) instead of maxInt64 as the comment saying.

(A possible fix could be:  `((naiveSum >> 63) ^ 1)`  =>  `int64((uint64(naiveSum)>>63)^1)`)

## To Reproduce

Steps to reproduce the behavior:
run this test:
```go
func TestCheckedAdd(t *testing.T) {
	var a, b int64
	a = math.MaxInt64
	b = 23
	
	fmt.Println(checkedAdd(a, b))  // output is: 9223372036854775805 
}
```

## Expected behavior
return maxInt64 when overflow.



Pull request description:
Fixed the behavior of checkedAdd when over/underflow
## Description

The [checkedAdd](https://github.com/maypok86/otter/blob/e57f61b947ff2308dd2e02ee181cef634b8dfd66/stats.go#L83) will return (maxInt64 - 2) instead of maxInt64 as the comment saying.

## Related issue(s)

- Fixes #91 

## :white_check_mark: Checklist for your Pull Request

<!--
Ideally a PR has all of the checkmarks set.

If something in this list is irrelevant to your PR, you should still set this
checkmark indicating that you are sure it is dealt with (be that by irrelevance).

If you don't set a checkmark (e. g. don't add a test for new functionality),
you must be able to justify that.
-->

#### Related changes (conditional)

- Tests
    - [ ] If I added new functionality, I added tests covering it.
    - [x] If I fixed a bug, I added a regression test to prevent the bug from
      silently reappearing again.

- Documentation
    - [x] I checked whether I should update the docs and did so if necessary:
        - [README](../README.md)

- Public contracts
    - [x] My changes doesn't break project license.

#### Stylistic guide (mandatory)

- [x] My code complies with the [styles guide](https://github.com/uber-go/guide/blob/master/style.md).
- [x] My commit history is clean (only contains changes relating to my
  issue/pull request and no reverted-my-earlier-commit changes) and commit
  messages start with identifiers of related issues in square brackets.

  **Example:** `[#42] Short commit description`

  If necessary both of these can be achieved even after the commits have been
  made/pushed using [rebase and squash](https://git-scm.com/docs/git-rebase).

#### Before merging (mandatory)
- [x] Check __target__  branch of PR is set correctly


Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 784f48a..f10638c 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -32,7 +32,6 @@ linters:
     - gosimple
     - govet
     - ineffassign
-    - interfacer
     - misspell
     - nakedret
     - nilerr
diff --git a/stats.go b/stats.go
index 90bcabd..c80b849 100644
--- a/stats.go
+++ b/stats.go
@@ -80,7 +80,10 @@ func checkedAdd(a, b int64) int64 {
 		return naiveSum
 	}
 	// we did over/under flow, if the sign is negative we should return math.MaxInt64 otherwise math.MinInt64.
-	return math.MaxInt64 + ((naiveSum >> 63) ^ 1)
+	if naiveSum < 0 {
+		return math.MaxInt64
+	}
+	return math.MinInt64
 }
 
 func negativeToMax(v int64) int64 {


Test patch:
diff --git a/stats_test.go b/stats_test.go
index 15253b5..4b5e7c7 100644
--- a/stats_test.go
+++ b/stats_test.go
@@ -17,6 +17,7 @@ package otter
 import (
 	"math"
 	"testing"
+	"unsafe"
 )
 
 func TestStats(t *testing.T) {
@@ -59,3 +60,29 @@ func TestStats(t *testing.T) {
 		t.Fatalf("not valid evicted cost. want %d, got %d", expected, s.EvictedCost())
 	}
 }
+
+func TestCheckedAdd_Overflow(t *testing.T) {
+	if unsafe.Sizeof(t) != 8 {
+		t.Skip()
+	}
+
+	a := int64(math.MaxInt64)
+	b := int64(23)
+
+	if got := checkedAdd(a, b); got != math.MaxInt64 {
+		t.Fatalf("wrong overflow in checkedAdd. want %d, got %d", int64(math.MaxInt64), got)
+	}
+}
+
+func TestCheckedAdd_Underflow(t *testing.T) {
+	if unsafe.Sizeof(t) != 8 {
+		t.Skip()
+	}
+
+	a := int64(math.MinInt64 + 10)
+	b := int64(-23)
+
+	if got := checkedAdd(a, b); got != math.MinInt64 {
+		t.Fatalf("wrong underflow in checkedAdd. want %d, got %d", int64(math.MinInt64), got)
+	}
+}