Skip to content

Commit e381e01

Browse files
committed
refactor: array and counter-based version of the stubs
1 parent 5f7fa0f commit e381e01

File tree

3 files changed

+97
-30
lines changed

3 files changed

+97
-30
lines changed

src/main/java/ewc/utilities/testableio/core/ConfigurableResponses.java renamed to src/main/java/ewc/utilities/testableio/core/SingleClientStubs.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,29 @@
3030
import lombok.SneakyThrows;
3131

3232
/**
33-
* This class provides configurable responses for HTTP-related utilities.
34-
* It is designed to be extended or modified to suit specific use cases.
33+
* This class provides configurable responses for all the queries made by a single 'client'.
3534
*
3635
* @since 0.1
3736
*/
38-
class ConfigurableResponses {
37+
class SingleClientStubs {
3938
/**
4039
* The storage for all the configured responses.
4140
*/
4241
private final Map<String, SingleQueryResponses> responses = new HashMap<>();
4342

4443
/**
45-
* Returns the next response for the given request.
44+
* Returns the next response for the given query.
4645
*
47-
* @param request The request for which to get the next response.
46+
* @param query The query for which to get the next response.
4847
* @return The next response object.
4948
*/
5049
@SneakyThrows
51-
public GenericResponse<?> nextResponseFor(final GenericRequest<?> request) {
50+
public GenericResponse<?> nextResponseFor(final GenericRequest<?> query) {
5251
final String key;
53-
if (this.responses.containsKey(ConfigurableResponses.responseKeyFor(request))) {
54-
key = ConfigurableResponses.responseKeyFor(request);
52+
if (this.responses.containsKey(SingleClientStubs.responseKeyFor(query))) {
53+
key = SingleClientStubs.responseKeyFor(query);
5554
} else {
56-
key = request.queryId();
55+
key = query.queryId();
5756
}
5857
if (!this.responses.containsKey(key)) {
5958
throw new NoSuchElementException("No responses configured");
@@ -72,11 +71,11 @@ public void setDefaultResponsesFor(final String query, final SingleQueryResponse
7271
public void setResponsesFor(
7372
final String client, final String query, final SingleQueryResponses response
7473
) {
75-
this.responses.put(ConfigurableResponses.responseKeyFor(client, query), response);
74+
this.responses.put(SingleClientStubs.responseKeyFor(client, query), response);
7675
}
7776

7877
private static String responseKeyFor(final GenericRequest<?> request) {
79-
return ConfigurableResponses.responseKeyFor(request.clientId(), request.queryId());
78+
return SingleClientStubs.responseKeyFor(request.clientId(), request.queryId());
8079
}
8180

8281
private static String responseKeyFor(final String client, final String query) {

src/main/java/ewc/utilities/testableio/core/SingleQueryResponses.java

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424

2525
package ewc.utilities.testableio.core;
2626

27-
import java.util.Arrays;
28-
import java.util.Iterator;
2927
import java.util.NoSuchElementException;
30-
import java.util.stream.Stream;
28+
import java.util.concurrent.atomic.AtomicInteger;
3129

3230
/**
3331
* This class provides configured responses for a single I/O opersation stub. The responses could
@@ -39,10 +37,14 @@
3937
*/
4038
public class SingleQueryResponses {
4139
/**
42-
* The iterator of configured responses. This iterator is used to provide
43-
* responses sequentially.
40+
* The counter providing the index of the next response to be returned.
4441
*/
45-
private final Iterator<? extends GenericResponse<?>> values;
42+
private final Counter index;
43+
44+
/**
45+
* The array of responses to be returned sequentially.
46+
*/
47+
private final GenericResponse<?>[] values;
4648

4749
/**
4850
* The short description of this instance. Used primarily for identifying the
@@ -57,7 +59,7 @@ public class SingleQueryResponses {
5759
* @param value The response to be returned forever.
5860
*/
5961
public SingleQueryResponses(final String stub, final GenericResponse<?> value) {
60-
this(Stream.generate(() -> value).iterator(), stub);
62+
this(stub, new GenericResponse<?>[]{value}, new ConstantIndex());
6163
}
6264

6365
/**
@@ -68,20 +70,22 @@ public SingleQueryResponses(final String stub, final GenericResponse<?> value) {
6870
* @param values The array of responses to be returned sequentially.
6971
*/
7072
public SingleQueryResponses(final String stub, final GenericResponse<?>... values) {
71-
this(Arrays.stream(values).iterator(), stub);
73+
this(stub, values, new IncrementalIndex());
7274
}
7375

7476
/**
7577
* Primary constructor.
7678
*
77-
* @param values The iterator that returns configured responses sequentially.
78-
* @param description The short description of this instance.
79+
* @param stub The short description of this stub instance.
80+
* @param values The array of responses to be returned sequentially.
81+
* @param index The counter providing the index of the next response to be returned.
7982
*/
8083
private SingleQueryResponses(
81-
final Iterator<? extends GenericResponse<?>> values, final String description
84+
final String stub, final GenericResponse<?>[] values, final Counter index
8285
) {
86+
this.index = index;
8387
this.values = values;
84-
this.description = description;
88+
this.description = stub;
8589
}
8690

8791
/**
@@ -95,15 +99,79 @@ public GenericResponse<?> next() {
9599
if (this.values == null) {
96100
throw new IllegalStateException("No response to send");
97101
}
98-
if (!this.values.hasNext()) {
102+
if (this.index.isTheLast(this.values.length)) {
99103
throw new NoSuchElementException(
100104
String.format("No more configured responses for %s", this.description)
101105
);
102106
}
103-
final GenericResponse<?> value = this.values.next();
107+
final GenericResponse<?> value = this.values[this.index.getAndIncrement()];
104108
if (value.contents() instanceof RuntimeException runtimeException) {
105109
throw runtimeException;
106110
}
107111
return value;
108112
}
113+
114+
/**
115+
* The value of the counter. This value is used to determine the index of the response to
116+
* be returned.
117+
*
118+
* @since 0.1
119+
*/
120+
private interface Counter {
121+
/**
122+
* The value of the counter. This value is used to determine the index of the response to
123+
* be returned.
124+
*
125+
* @return The current value of the counter.
126+
*/
127+
int currentValue();
128+
129+
/**
130+
* Increments the counter by one. This method is used to move to the next response in the
131+
* array.
132+
*
133+
* @return The value of the counter before incrementing.
134+
*/
135+
int getAndIncrement();
136+
137+
/**
138+
* Checks if the current value of the counter is the last one in the array.
139+
*
140+
* @param size The size of the array of responses.
141+
* @return True if the current value is the last one, false otherwise.
142+
* @since 0.1
143+
*/
144+
default boolean isTheLast(final int size) {
145+
return this.currentValue() >= size;
146+
}
147+
}
148+
149+
private static final class ConstantIndex implements Counter {
150+
@Override
151+
public int currentValue() {
152+
return 0;
153+
}
154+
155+
@Override
156+
public int getAndIncrement() {
157+
return 0;
158+
}
159+
}
160+
161+
private static final class IncrementalIndex implements Counter {
162+
/**
163+
* The thread-safe counter providing the index of the next response to be returned.
164+
*/
165+
private final AtomicInteger index = new AtomicInteger(0);
166+
167+
@Override
168+
public int currentValue() {
169+
return this.index.intValue();
170+
}
171+
172+
@Override
173+
public int getAndIncrement() {
174+
return this.index.getAndIncrement();
175+
}
176+
}
109177
}

src/test/java/ewc/utilities/testableio/core/ConfigurableResponsesTest.java renamed to src/test/java/ewc/utilities/testableio/core/SingleClientStubsTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@
3131
import org.junit.jupiter.api.Test;
3232

3333
/**
34-
* This class provides unit tests for the {@link ConfigurableResponses} class.
34+
* This class provides unit tests for the {@link SingleClientStubs} class.
3535
* It verifies the default values and behavior of the class.
3636
*
3737
* @since 0.1
3838
*/
39-
final class ConfigurableResponsesTest {
39+
final class SingleClientStubsTest {
4040
@Test
4141
void couldBeInstantiated() {
42-
final ConfigurableResponses target = new ConfigurableResponses();
42+
final SingleClientStubs target = new SingleClientStubs();
4343
Assertions.assertThat(target).isNotNull();
4444
}
4545

4646
@Test
4747
void throwsIfNoResponsesConfigured() {
48-
final ConfigurableResponses target = new ConfigurableResponses();
48+
final SingleClientStubs target = new SingleClientStubs();
4949
final GenericRequest<String> request = new MockRequest().assignedToClient();
5050
Assertions.assertThatExceptionOfType(NoSuchElementException.class)
5151
.isThrownBy(() -> target.nextResponseFor(request))
@@ -54,7 +54,7 @@ void throwsIfNoResponsesConfigured() {
5454

5555
@Test
5656
void returnsTheResponseThatCorrespondsToTheRequest() {
57-
final ConfigurableResponses target = new ConfigurableResponses();
57+
final SingleClientStubs target = new SingleClientStubs();
5858
target.setDefaultResponsesFor(
5959
"getHomePage",
6060
new SingleQueryResponses(

0 commit comments

Comments
 (0)