Repository: mockito/mockito
Issue: Regression with InOrder verification after #2369

The following test starts failing after https://github.com/mockito/mockito/commit/123beb8311ed6303ba71d682cff8434fe36b7f0f. It looks like the change to call actual `equals` and `hashCode` methods is catching a call to `equals` inside the implementation of `InOrder`.

```java
package com.test;

import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.spy;

import org.junit.Test;
import org.mockito.InOrder;

public class AppTest {

  static class Foo {
    void foo() {}
  }

  @Test
  public void test() {
    Foo mock1 = spy(new Foo());
    Foo mock2 = spy(new Foo());
    mock1.foo();
    InOrder order = inOrder(mock1, mock2);
    order.verify(mock1).foo();
    order.verifyNoMoreInteractions();
  }
}
```

```
No interactions wanted here:
-> at com.test.AppTest.test(AppTest.java:22)
But found this interaction on mock 'foo':
-> at java.base/java.util.LinkedList.indexOf(LinkedList.java:609)
	at com.test.AppTest.test(AppTest.java:22)
```

Issue comments:
I am experiencing a similar issue after upgrading to version 3.12.0.
More specifically, the `AnnotatedSagaRepositoryTest#testLoadedFromNestedUnitOfWorkAfterCreateAndStore` test (found [here](https://github.com/AxonFramework/AxonFramework/blob/2eeacc4e225d0f3739b0c7d4e4ba37358795407c/modelling/src/test/java/org/axonframework/modelling/saga/repository/AnnotatedSagaRepositoryTest.java#L91)) has started failing, and it follows a similar pattern as described by @cushon.
You can find the failing issue in the GitHub Actions under Axon Framework issue [#1913](https://github.com/AxonFramework/AxonFramework/pull/1913).
Thanks for reporting! Taking a look now to figure out what is going on here.
Fix up at #2395
3.12.1 is currently being pushed to Maven Central. It should be available in a couple of hours.
Thanks for the quick fix here, @TimvdLippe. I can confirm that 3.12.1 solved the aforementioned problem for Axon Framework.

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/InOrderImpl.java b/src/main/java/org/mockito/internal/InOrderImpl.java
index 7fc0b5f27a..af852e49ae 100644
--- a/src/main/java/org/mockito/internal/InOrderImpl.java
+++ b/src/main/java/org/mockito/internal/InOrderImpl.java
@@ -6,7 +6,7 @@
 
 import static org.mockito.internal.exceptions.Reporter.inOrderRequiresFamiliarMock;
 
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.mockito.InOrder;
@@ -31,7 +31,7 @@
 public class InOrderImpl implements InOrder, InOrderContext {
 
     private final MockitoCore mockitoCore = new MockitoCore();
-    private final List<Object> mocksToBeVerifiedInOrder = new LinkedList<>();
+    private final List<Object> mocksToBeVerifiedInOrder = new ArrayList<>();
     private final InOrderContext inOrderContext = new InOrderContextImpl();
 
     public List<Object> getMocksToBeVerifiedInOrder() {
@@ -56,7 +56,7 @@ public <T> T verify(T mock, VerificationMode mode) {
         if (!mockingDetails.isMock()) {
             throw notAMockPassedToVerify(mock.getClass());
         }
-        if (!mocksToBeVerifiedInOrder.contains(mock)) {
+        if (!this.objectIsMockToBeVerified(mock)) {
             throw inOrderRequiresFamiliarMock();
         }
         if (mode instanceof VerificationWrapper) {
@@ -69,6 +69,20 @@ public <T> T verify(T mock, VerificationMode mode) {
         return mockitoCore.verify(mock, new InOrderWrapper((VerificationInOrderMode) mode, this));
     }
 
+    // We can't use `this.mocksToBeVerifiedInOrder.contains`, since that in turn calls `.equals` on
+    // the mock. Since mocks can be spies and spies get their real equals method calls called, the
+    // result is that Mockito incorrectly would register an invocation on a mock. This normally
+    // wouldn't be a problem, unless the user explicitly verifies that no interactions are performed
+    // on the mock, which would start to fail for the equals invocation.
+    private boolean objectIsMockToBeVerified(Object mock) {
+        for (Object inOrderMock : this.mocksToBeVerifiedInOrder) {
+            if (inOrderMock == mock) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public boolean isVerified(Invocation i) {
         return inOrderContext.isVerified(i);


Test patch:
diff --git a/src/test/java/org/mockitousage/spies/SpiesWithRealEqualsAndInOrderTest.java b/src/test/java/org/mockitousage/spies/SpiesWithRealEqualsAndInOrderTest.java
new file mode 100644
index 0000000000..e2dabe9515
--- /dev/null
+++ b/src/test/java/org/mockitousage/spies/SpiesWithRealEqualsAndInOrderTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.spies;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.inOrder;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+// https://github.com/mockito/mockito/issues/2394
+public class SpiesWithRealEqualsAndInOrderTest {
+
+    @Test
+    public void should_be_able_to_handle_in_order_on_spies_with_equals() {
+        ToBeSpied mock1 = spy(new ToBeSpied());
+        ToBeSpied mock2 = spy(new ToBeSpied());
+        mock1.someMethod();
+        InOrder order = inOrder(mock1, mock2);
+        order.verify(mock1).someMethod();
+        order.verifyNoMoreInteractions();
+    }
+
+    static class ToBeSpied {
+        void someMethod() {}
+    }
+}