summaryrefslogtreecommitdiff
path: root/src/main/java/au/id
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-06 16:40:04 +1000
committerCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-06 16:40:04 +1000
commit84f0f216b4643601e4b8760d190b087bbce98bd4 (patch)
tree5f9ea5c1087b5da6611c9a9c51ba076e55e4e9e3 /src/main/java/au/id
parent05ec409ce96da92d430c4a8e58b08d46f42d667a (diff)
Lots of work on the stateful checking stuff: it's a fair bit nicer now
Diffstat (limited to 'src/main/java/au/id')
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/Generators.java3
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/Command.java18
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/CommandList.java51
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/CommandListGenerator.java22
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/CommandResult.java12
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/CommandValue.java22
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/state/GeneratedCommand.java12
7 files changed, 83 insertions, 57 deletions
diff --git a/src/main/java/au/id/zancanaro/javacheck/Generators.java b/src/main/java/au/id/zancanaro/javacheck/Generators.java
index 619fe2d..f4ac025 100644
--- a/src/main/java/au/id/zancanaro/javacheck/Generators.java
+++ b/src/main/java/au/id/zancanaro/javacheck/Generators.java
@@ -40,7 +40,8 @@ public final class Generators {
return integer(0, gens.length).flatMap(index -> gens[index].map(x -> (T) x));
}
- public static <T> Generator<T> elements(T[] elements) {
+ @SafeVarargs
+ public static <T> Generator<T> elements(T... elements) {
return elements(Arrays.asList(elements));
}
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/Command.java b/src/main/java/au/id/zancanaro/javacheck/state/Command.java
index afa3957..78df8f1 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/Command.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/Command.java
@@ -2,22 +2,26 @@ package au.id.zancanaro.javacheck.state;
import au.id.zancanaro.javacheck.Generator;
-public abstract class Command<State,Args,Result> {
- public Generator<Args> argsGenerator(State state) {
+public abstract class Command<S, A, R> {
+ public Generator<A> argsGenerator(S state) {
return Generator.pure(null);
}
- public boolean preCondition(State state, Args args) {
+ public boolean preCondition(S state, A args) {
return true;
}
- public abstract Result runCommand(Args args);
+ public abstract R runCommand(S state, A args) throws Throwable;
- public State nextState(State state, Args args, CommandValue<Result> result) {
+ public S nextState(S state, A args, CommandValue<R> result) {
return state;
}
- public boolean postCondition(State oldState, State newState, Args args, Result result) {
- return true;
+ public void postCondition(S oldState, S newState, A args, R result) throws Throwable {
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
}
}
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/CommandList.java b/src/main/java/au/id/zancanaro/javacheck/state/CommandList.java
index 0426fd3..05000f2 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/CommandList.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/CommandList.java
@@ -2,17 +2,17 @@ package au.id.zancanaro.javacheck.state;
import java.util.*;
-public class CommandList<State> {
- private final List<GeneratedCommand<State, ?, ?>> commands;
+public class CommandList<S> {
+ private final List<GeneratedCommand<S, ?, ?>> commands;
- public CommandList(List<GeneratedCommand<State, ?, ?>> commands) {
+ public CommandList(List<GeneratedCommand<S, ?, ?>> commands) {
this.commands = new ArrayList<>(commands);
}
- public CommandResult<State> run(State initialState) {
+ public CommandResult<S> run(S initialState) {
Map<Integer, Object> values = new HashMap<>();
- CommandResult<State> result = CommandResult.success(initialState);
- for (GeneratedCommand<State, ?, ?> generated : commands) {
+ CommandResult<S> result = CommandResult.success(initialState);
+ for (GeneratedCommand<S, ?, ?> generated : commands) {
result = runRealCommand(generated, result.getState(), values);
if (result.isFailed()) {
break;
@@ -21,26 +21,27 @@ public class CommandList<State> {
return result;
}
- private static <State, Args, Result> CommandResult<State> runRealCommand(
- GeneratedCommand<State, Args, Result> generated,
- State state,
+ private static <S, A, R> CommandResult<S> runRealCommand(
+ GeneratedCommand<S, A, R> generated,
+ S state,
Map<Integer, Object> values) {
int id = generated.getId();
- Command<State, Args, Result> command = generated.getCommand();
- Args args = generated.getArgs();
+ Command<S, A, R> command = generated.getCommand();
+ A args = generated.getArgs();
try {
if (!command.preCondition(state, args)) {
return CommandResult.fail(state, new Error("Precondition failed"));
}
- Result result = CommandValue.withValues(values, () ->
- command.runCommand(args));
+ final S oldState = state;
+ R result = CommandValue.withValues(values, () -> command.runCommand(oldState, args));
values.put(id, result);
- final State oldState = state;
- final State newState = CommandValue.withValues(values, () ->
+ final S newState = CommandValue.withValues(values, () ->
command.nextState(oldState, args, new CommandValue<>(id)));
state = newState;
- if (!CommandValue.withValues(values, () -> command.postCondition(oldState, newState, args, result))) {
- return CommandResult.fail(state, new Error("Postcondition failed"));
+ try {
+ CommandValue.withValues(values, () -> command.postCondition(oldState, newState, args, result));
+ } catch (Throwable ex) {
+ return CommandResult.fail(state, ex);
}
return CommandResult.success(state);
} catch (Throwable ex) {
@@ -48,12 +49,12 @@ public class CommandList<State> {
}
}
- private static <State, Args, Result> CommandResult<State> runAbstractCommand(
- GeneratedCommand<State, Args, Result> generated,
- State state) {
+ private static <S, A, R> CommandResult<S> runAbstractCommand(
+ GeneratedCommand<S, A, R> generated,
+ S state) {
int id = generated.getId();
- Command<State, Args, Result> command = generated.getCommand();
- Args args = generated.getArgs();
+ Command<S, A, R> command = generated.getCommand();
+ A args = generated.getArgs();
try {
if (!command.preCondition(state, args)) {
return CommandResult.fail(state, new Error("Precondition failed"));
@@ -66,8 +67,8 @@ public class CommandList<State> {
}
public boolean isValid() {
- CommandResult<State> result = CommandResult.success(null);
- for (GeneratedCommand<State, ?, ?> generated : commands) {
+ CommandResult<S> result = CommandResult.success(null);
+ for (GeneratedCommand<S, ?, ?> generated : commands) {
result = runAbstractCommand(generated, result.getState());
if (result.isFailed()) {
break;
@@ -79,7 +80,7 @@ public class CommandList<State> {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- Iterator<GeneratedCommand<State, ?, ?>> iterator = commands.iterator();
+ Iterator<GeneratedCommand<S, ?, ?>> iterator = commands.iterator();
while (iterator.hasNext()) {
builder.append(iterator.next());
if (iterator.hasNext()) {
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/CommandListGenerator.java b/src/main/java/au/id/zancanaro/javacheck/state/CommandListGenerator.java
index 4c2c47f..1600f07 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/CommandListGenerator.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/CommandListGenerator.java
@@ -9,38 +9,40 @@ import java.util.function.Function;
import static au.id.zancanaro.javacheck.Generator.pure;
import static au.id.zancanaro.javacheck.Generators.noShrink;
-public class CommandListGenerator<State> implements Generator<CommandList<State>> {
- private final Function<State, Generator<Command<State, ?, ?>>> generateCommand;
+public class CommandListGenerator<S> implements Generator<CommandList<S>> {
+ private final S initialState;
+ private final Function<S, Generator<Command<S, ?, ?>>> generateCommand;
- public CommandListGenerator(Function<State, Generator<Command<State, ?, ?>>> generateCommand) {
+ public CommandListGenerator(S initialState, Function<S, Generator<Command<S, ?, ?>>> generateCommand) {
+ this.initialState = initialState;
this.generateCommand = generateCommand;
}
- public Generator<GeneratedCommand<State, ?, ?>> commandGenerator(int id, State state) {
+ public Generator<GeneratedCommand<S, ?, ?>> commandGenerator(int id, S state) {
return noShrink(generateCommand.apply(state))
.flatMap(command -> generateSingleCommand(id, command, state));
}
- public <Args, Result> Generator<GeneratedCommand<State, ?, ?>> generateSingleCommand(int id, Command<State, Args, Result> command, State state) {
+ public <A, R> Generator<GeneratedCommand<S, ?, ?>> generateSingleCommand(int id, Command<S, A, R> command, S state) {
return command.argsGenerator(state).flatMap(generatedArgs ->
command.preCondition(state, generatedArgs) ?
pure(new GeneratedCommand<>(id, command, generatedArgs)) :
commandGenerator(id, state));
}
- public <Args, Result> State nextState(int id, GeneratedCommand<State, Args, Result> generatedCommand, State state) {
+ public <A, R> S nextState(int id, GeneratedCommand<S, A, R> generatedCommand, S state) {
return generatedCommand.getCommand().nextState(state, generatedCommand.getArgs(), new CommandValue<>(id));
}
@Override
- public ShrinkTree<CommandList<State>> generate(Random random, int size) {
+ public ShrinkTree<CommandList<S>> generate(Random random, int size) {
int count = random.nextInt(size);
@SuppressWarnings("unchecked")
- ShrinkTree<GeneratedCommand<State, ?, ?>>[] commandTrees = (ShrinkTree<GeneratedCommand<State, ?, ?>>[]) new ShrinkTree[count];
- State state = null;
+ ShrinkTree<GeneratedCommand<S, ?, ?>>[] commandTrees = (ShrinkTree<GeneratedCommand<S, ?, ?>>[]) new ShrinkTree[count];
+ S state = initialState;
for (int i = 0; i < count; ++i) {
commandTrees[i] = commandGenerator(i, state).generate(random, size);
- GeneratedCommand<State, ?, ?> generatedCommand = commandTrees[i].getValue();
+ GeneratedCommand<S, ?, ?> generatedCommand = commandTrees[i].getValue();
state = nextState(i, generatedCommand, state);
}
return ShrinkTree.combine(commandTrees, ShrinkTree::removeAndPromoteChildren)
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/CommandResult.java b/src/main/java/au/id/zancanaro/javacheck/state/CommandResult.java
index 12f650d..cc2f5ba 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/CommandResult.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/CommandResult.java
@@ -1,15 +1,15 @@
package au.id.zancanaro.javacheck.state;
-public class CommandResult<State> {
- private final State state;
+public class CommandResult<S> {
+ private final S state;
private final Throwable thrown;
- private CommandResult(State state, Throwable thrown) {
+ private CommandResult(S state, Throwable thrown) {
this.state = state;
this.thrown = thrown;
}
- public State getState() {
+ public S getState() {
return state;
}
@@ -21,11 +21,11 @@ public class CommandResult<State> {
return thrown;
}
- public static <State> CommandResult<State> success(State state) {
+ public static <S> CommandResult<S> success(S state) {
return new CommandResult<>(state, null);
}
- public static <State> CommandResult<State> fail(State state, Throwable ex) {
+ public static <S> CommandResult<S> fail(S state, Throwable ex) {
return new CommandResult<>(state, ex);
}
}
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/CommandValue.java b/src/main/java/au/id/zancanaro/javacheck/state/CommandValue.java
index 8d3f272..8584fc7 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/CommandValue.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/CommandValue.java
@@ -5,13 +5,31 @@ import java.util.NoSuchElementException;
import java.util.function.Supplier;
public class CommandValue<T> {
+ public static interface Action<T> {
+ T doAction() throws Throwable;
+ }
+
+ public static interface VoidAction {
+ void doAction() throws Throwable;
+ }
+
private static Map<Integer, Object> values = null;
- public static <T> T withValues(Map<Integer, Object> newValues, Supplier<T> action) {
+ public static <T> T withValues(Map<Integer, Object> newValues, Action<T> action) throws Throwable {
+ Map<Integer,Object> oldValues = values;
+ try {
+ values = newValues;
+ return action.doAction();
+ } finally {
+ values = oldValues;
+ }
+ }
+
+ public static void withValues(Map<Integer, Object> newValues, VoidAction action) throws Throwable {
Map<Integer,Object> oldValues = values;
try {
values = newValues;
- return action.get();
+ action.doAction();
} finally {
values = oldValues;
}
diff --git a/src/main/java/au/id/zancanaro/javacheck/state/GeneratedCommand.java b/src/main/java/au/id/zancanaro/javacheck/state/GeneratedCommand.java
index 90d9a47..23f306b 100644
--- a/src/main/java/au/id/zancanaro/javacheck/state/GeneratedCommand.java
+++ b/src/main/java/au/id/zancanaro/javacheck/state/GeneratedCommand.java
@@ -1,11 +1,11 @@
package au.id.zancanaro.javacheck.state;
-public class GeneratedCommand<State, Args, Result> {
+public class GeneratedCommand<S, A, R> {
private final int id;
- private final Command<State, Args, Result> command;
- private final Args args;
+ private final Command<S, A, R> command;
+ private final A args;
- public GeneratedCommand(int id, Command<State, Args, Result> command, Args args) {
+ public GeneratedCommand(int id, Command<S, A, R> command, A args) {
this.id = id;
this.command = command;
this.args = args;
@@ -15,11 +15,11 @@ public class GeneratedCommand<State, Args, Result> {
return id;
}
- public Command<State, Args, Result> getCommand() {
+ public Command<S, A, R> getCommand() {
return command;
}
- public Args getArgs() {
+ public A getArgs() {
return args;
}