From b28643b27832c7c70f7e5dd24d4d9f6760231a77 Mon Sep 17 00:00:00 2001 From: John Pyeatt Date: Mon, 17 Jan 2022 18:53:10 -0600 Subject: [PATCH 1/3] Issue-2544 Fixed bug when more than 2 invocations in Mockito.mockConstructionWithAnswer(). If you build a mockConstructionWithAnswer with more than 1 additionalAnswers there was a logic error whereby the method would return the wrong value when making the second last invocation. It would accidentally think it's at the end an only return the last answer, never returning the second last answer when it should. The changes I made to ConstructionMockTest.java now exercises this condition. --- src/main/java/org/mockito/Mockito.java | 2 +- .../test/java/org/mockitoinline/ConstructionMockTest.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java index a0502a6eec..8c1a0cff9b 100644 --- a/src/main/java/org/mockito/Mockito.java +++ b/src/main/java/org/mockito/Mockito.java @@ -2185,7 +2185,7 @@ public static MockedConstruction mockConstructionWithAnswer( context -> { if (context.getCount() == 1 || additionalAnswers.length == 0) { return withSettings().defaultAnswer(defaultAnswer); - } else if (context.getCount() >= additionalAnswers.length) { + } else if (context.getCount() > additionalAnswers.length) { return withSettings() .defaultAnswer(additionalAnswers[additionalAnswers.length - 1]); } else { diff --git a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java index 4195080814..cb5298a208 100644 --- a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java +++ b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java @@ -50,10 +50,11 @@ public void testConstructionMockDefaultAnswer() { @Test public void testConstructionMockDefaultAnswerMultiple() { - try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux")) { + try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux", invocation -> "baz")) { assertEquals("bar", new Dummy().foo()); assertEquals("qux", new Dummy().foo()); - assertEquals("qux", new Dummy().foo()); + assertEquals("baz", new Dummy().foo()); + assertEquals("baz", new Dummy().foo()); } } From 7f4e5d10d89e8b7cb2d190bb0f643b1d3c12ca3a Mon Sep 17 00:00:00 2001 From: John Pyeatt Date: Mon, 17 Jan 2022 18:53:10 -0600 Subject: [PATCH 2/3] Fixes #2544 - when more than 2 invocations in Mockito.mockConstructionWithAnswer(). If you build a mockConstructionWithAnswer with more than 1 additionalAnswers there was a logic error whereby the method would return the wrong value when making the second last invocation. It would accidentally think it's at the end an only return the last answer, never returning the second last answer when it should. The changes I made to ConstructionMockTest.java now exercises this condition. --- src/main/java/org/mockito/Mockito.java | 2 +- .../test/java/org/mockitoinline/ConstructionMockTest.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java index a0502a6eec..8c1a0cff9b 100644 --- a/src/main/java/org/mockito/Mockito.java +++ b/src/main/java/org/mockito/Mockito.java @@ -2185,7 +2185,7 @@ public static MockedConstruction mockConstructionWithAnswer( context -> { if (context.getCount() == 1 || additionalAnswers.length == 0) { return withSettings().defaultAnswer(defaultAnswer); - } else if (context.getCount() >= additionalAnswers.length) { + } else if (context.getCount() > additionalAnswers.length) { return withSettings() .defaultAnswer(additionalAnswers[additionalAnswers.length - 1]); } else { diff --git a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java index 4195080814..cb5298a208 100644 --- a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java +++ b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java @@ -50,10 +50,11 @@ public void testConstructionMockDefaultAnswer() { @Test public void testConstructionMockDefaultAnswerMultiple() { - try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux")) { + try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux", invocation -> "baz")) { assertEquals("bar", new Dummy().foo()); assertEquals("qux", new Dummy().foo()); - assertEquals("qux", new Dummy().foo()); + assertEquals("baz", new Dummy().foo()); + assertEquals("baz", new Dummy().foo()); } } From 49f8551813a9ef8e3fdd51fcb4a22acdd7f2bc5d Mon Sep 17 00:00:00 2001 From: John Pyeatt Date: Tue, 18 Jan 2022 08:58:14 -0600 Subject: [PATCH 3/3] Fixed #2544 unit test change based on request from TimvdLippe I restored testConstructionMockDefaultAnswer() in ConstructionMockTest to it's original 2-invocation form. I added new test, testConstructionMockDefaultAnswerMultipleMoreThanTwo() to demonstrate the code is now fixed when more than 2 invocations are in place. --- .../java/org/mockitoinline/ConstructionMockTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java index cb5298a208..7eb87c5702 100644 --- a/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java +++ b/subprojects/inline/src/test/java/org/mockitoinline/ConstructionMockTest.java @@ -50,6 +50,18 @@ public void testConstructionMockDefaultAnswer() { @Test public void testConstructionMockDefaultAnswerMultiple() { + try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux")) { + assertEquals("bar", new Dummy().foo()); + assertEquals("qux", new Dummy().foo()); + assertEquals("qux", new Dummy().foo()); + } + } + + /** + * Tests issue #2544 + */ + @Test + public void testConstructionMockDefaultAnswerMultipleMoreThanTwo() { try (MockedConstruction ignored = Mockito.mockConstructionWithAnswer(Dummy.class, invocation -> "bar", invocation -> "qux", invocation -> "baz")) { assertEquals("bar", new Dummy().foo()); assertEquals("qux", new Dummy().foo());