[commands] Add property tests for command compositions (#4715)

This commit is contained in:
Starlight220
2022-11-28 02:23:56 +02:00
committed by GitHub
parent e4ac09077c
commit 8958b2a4da
31 changed files with 579 additions and 59 deletions

View File

@@ -9,6 +9,7 @@ import static org.mockito.Mockito.when;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj2.command.Command.InterruptionBehavior;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
@@ -47,6 +48,7 @@ public class CommandTestBase {
when(m_mockCommand.getRequirements()).thenReturn(Set.of(requirements));
when(m_mockCommand.isFinished()).thenReturn(false);
when(m_mockCommand.runsWhenDisabled()).thenReturn(runWhenDisabled);
when(m_mockCommand.getInterruptionBehavior()).thenReturn(InterruptionBehavior.kCancelSelf);
}
public Command getMock() {

View File

@@ -0,0 +1,115 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj2.command;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import edu.wpi.first.wpilibj2.command.Command.InterruptionBehavior;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
interface MultiCompositionTestBase<T extends Command> extends SingleCompositionTestBase<T> {
T compose(Command... members);
@Override
default T composeSingle(Command member) {
return compose(member);
}
static Stream<Arguments> interruptible() {
return Stream.of(
arguments(
"AllCancelSelf",
InterruptionBehavior.kCancelSelf,
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf)),
arguments(
"AllCancelIncoming",
InterruptionBehavior.kCancelIncoming,
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming)),
arguments(
"TwoCancelSelfOneIncoming",
InterruptionBehavior.kCancelSelf,
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming)),
arguments(
"TwoCancelIncomingOneSelf",
InterruptionBehavior.kCancelSelf,
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelIncoming),
new WaitUntilCommand(() -> false)
.withInterruptBehavior(InterruptionBehavior.kCancelSelf)));
}
@MethodSource
@ParameterizedTest(name = "interruptible[{index}]: {0}")
default void interruptible(
@SuppressWarnings("unused") String name,
InterruptionBehavior expected,
Command command1,
Command command2,
Command command3) {
var command = compose(command1, command2, command3);
assertEquals(expected, command.getInterruptionBehavior());
}
static Stream<Arguments> runsWhenDisabled() {
return Stream.of(
arguments(
"AllFalse",
false,
new WaitUntilCommand(() -> false).ignoringDisable(false),
new WaitUntilCommand(() -> false).ignoringDisable(false),
new WaitUntilCommand(() -> false).ignoringDisable(false)),
arguments(
"AllTrue",
true,
new WaitUntilCommand(() -> false).ignoringDisable(true),
new WaitUntilCommand(() -> false).ignoringDisable(true),
new WaitUntilCommand(() -> false).ignoringDisable(true)),
arguments(
"TwoTrueOneFalse",
false,
new WaitUntilCommand(() -> false).ignoringDisable(true),
new WaitUntilCommand(() -> false).ignoringDisable(true),
new WaitUntilCommand(() -> false).ignoringDisable(false)),
arguments(
"TwoFalseOneTrue",
false,
new WaitUntilCommand(() -> false).ignoringDisable(false),
new WaitUntilCommand(() -> false).ignoringDisable(false),
new WaitUntilCommand(() -> false).ignoringDisable(true)));
}
@MethodSource
@ParameterizedTest(name = "runsWhenDisabled[{index}]: {0}")
default void runsWhenDisabled(
@SuppressWarnings("unused") String name,
boolean expected,
Command command1,
Command command2,
Command command3) {
var command = compose(command1, command2, command3);
assertEquals(expected, command.runsWhenDisabled());
}
}

View File

@@ -14,7 +14,8 @@ import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
class ParallelCommandGroupTest extends CommandTestBase {
class ParallelCommandGroupTest extends CommandTestBase
implements MultiCompositionTestBase<ParallelCommandGroup> {
@Test
void parallelGroupScheduleTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -126,4 +127,9 @@ class ParallelCommandGroupTest extends CommandTestBase {
assertThrows(
IllegalArgumentException.class, () -> new ParallelCommandGroup(command1, command2));
}
@Override
public ParallelCommandGroup compose(Command... members) {
return new ParallelCommandGroup(members);
}
}

View File

@@ -11,9 +11,11 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class ParallelDeadlineGroupTest extends CommandTestBase {
class ParallelDeadlineGroupTest extends CommandTestBase
implements MultiCompositionTestBase<ParallelDeadlineGroup> {
@Test
void parallelDeadlineScheduleTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -122,4 +124,9 @@ class ParallelDeadlineGroupTest extends CommandTestBase {
assertThrows(
IllegalArgumentException.class, () -> new ParallelDeadlineGroup(command1, command2));
}
@Override
public ParallelDeadlineGroup compose(Command... members) {
return new ParallelDeadlineGroup(members[0], Arrays.copyOfRange(members, 1, members.length));
}
}

View File

@@ -16,7 +16,8 @@ import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
class ParallelRaceGroupTest extends CommandTestBase {
class ParallelRaceGroupTest extends CommandTestBase
implements MultiCompositionTestBase<ParallelRaceGroup> {
@Test
void parallelRaceScheduleTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -202,4 +203,9 @@ class ParallelRaceGroupTest extends CommandTestBase {
assertFalse(scheduler.isScheduled(group));
}
}
@Override
public ParallelRaceGroup compose(Command... members) {
return new ParallelRaceGroup(members);
}
}

View File

@@ -9,11 +9,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
class RepeatCommandTest extends CommandTestBase {
class RepeatCommandTest extends CommandTestBase
implements SingleCompositionTestBase<RepeatCommand> {
@Test
void callsMethodsCorrectly() {
var initCounter = new AtomicInteger(0);
@@ -66,18 +64,8 @@ class RepeatCommandTest extends CommandTestBase {
assertEquals(1, endCounter.get());
}
@EnumSource(Command.InterruptionBehavior.class)
@ParameterizedTest
void interruptible(Command.InterruptionBehavior interruptionBehavior) {
var command =
new WaitUntilCommand(() -> false).withInterruptBehavior(interruptionBehavior).repeatedly();
assertEquals(interruptionBehavior, command.getInterruptionBehavior());
}
@ValueSource(booleans = {true, false})
@ParameterizedTest
void runWhenDisabled(boolean runsWhenDisabled) {
var command = new WaitUntilCommand(() -> false).ignoringDisable(runsWhenDisabled).repeatedly();
assertEquals(runsWhenDisabled, command.runsWhenDisabled());
@Override
public RepeatCommand composeSingle(Command member) {
return member.repeatedly();
}
}

View File

@@ -9,10 +9,11 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
class SelectCommandTest extends CommandTestBase {
class SelectCommandTest extends CommandTestBase implements MultiCompositionTestBase<SelectCommand> {
@Test
void selectCommandTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -105,4 +106,13 @@ class SelectCommandTest extends CommandTestBase {
verify(command3, never()).end(true);
}
}
@Override
public SelectCommand compose(Command... members) {
var map = new HashMap<Object, Command>();
for (int i = 0; i < members.length; i++) {
map.put(i, members[i]);
}
return new SelectCommand(map, () -> 0);
}
}

View File

@@ -12,7 +12,8 @@ import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
class SequentialCommandGroupTest extends CommandTestBase {
class SequentialCommandGroupTest extends CommandTestBase
implements MultiCompositionTestBase<SequentialCommandGroup> {
@Test
void sequentialGroupScheduleTest() {
try (CommandScheduler scheduler = new CommandScheduler()) {
@@ -121,4 +122,9 @@ class SequentialCommandGroupTest extends CommandTestBase {
assertTrue(scheduler.isScheduled(command3));
}
}
@Override
public SequentialCommandGroup compose(Command... members) {
return new SequentialCommandGroup(members);
}
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj2.command;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
public interface SingleCompositionTestBase<T extends Command> {
T composeSingle(Command member);
@EnumSource(Command.InterruptionBehavior.class)
@ParameterizedTest
default void interruptible(Command.InterruptionBehavior interruptionBehavior) {
var command =
composeSingle(
new WaitUntilCommand(() -> false).withInterruptBehavior(interruptionBehavior));
assertEquals(interruptionBehavior, command.getInterruptionBehavior());
}
@ValueSource(booleans = {true, false})
@ParameterizedTest
default void runWhenDisabled(boolean runsWhenDisabled) {
var command =
composeSingle(new WaitUntilCommand(() -> false).ignoringDisable(runsWhenDisabled));
assertEquals(runsWhenDisabled, command.runsWhenDisabled());
}
}