Skip to content

Commit a4987ec

Browse files
authored
Add tests for Truth Subjects (#152)
1 parent 8547ee7 commit a4987ec

9 files changed

Lines changed: 500 additions & 0 deletions
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import java.util.List;
19+
import java.util.stream.Stream;
20+
import org.junit.jupiter.api.extension.ExtensionContext;
21+
import org.junit.jupiter.params.provider.Arguments;
22+
import org.junit.jupiter.params.provider.ArgumentsProvider;
23+
import org.junit.jupiter.params.support.ParameterDeclarations;
24+
25+
interface Component {
26+
27+
Type getType();
28+
29+
enum Type {
30+
TRANSLATION,
31+
ROTATION
32+
}
33+
34+
abstract class ComponentArgumentsProvider<T extends Component> implements ArgumentsProvider {
35+
private final List<T> values;
36+
37+
protected ComponentArgumentsProvider(Type componentType, Stream<T> allValues) {
38+
values = allValues.filter(c -> c.getType() == componentType).toList();
39+
}
40+
41+
@Override
42+
public final Stream<? extends Arguments> provideArguments(
43+
ParameterDeclarations parameters, ExtensionContext context) {
44+
return values.stream().map(Arguments::of);
45+
}
46+
}
47+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import edu.wpi.first.math.geometry.Pose2d;
19+
import edu.wpi.first.math.geometry.Rotation2d;
20+
import edu.wpi.first.math.geometry.Translation2d;
21+
import java.util.stream.Stream;
22+
23+
/** Represents component in a two-dimensional coordinate system. */
24+
enum Pose2dComponent implements Component {
25+
X(Type.TRANSLATION) {
26+
@Override
27+
Pose2d add(Pose2d pose, double value) {
28+
return new Pose2d(pose.getX() + value, pose.getY(), pose.getRotation());
29+
}
30+
},
31+
Y(Type.TRANSLATION) {
32+
@Override
33+
Pose2d add(Pose2d pose, double value) {
34+
return new Pose2d(pose.getX(), pose.getY() + value, pose.getRotation());
35+
}
36+
},
37+
R(Type.ROTATION) {
38+
@Override
39+
Pose2d add(Pose2d pose, double value) {
40+
return new Pose2d(
41+
pose.getTranslation(), new Rotation2d(pose.getRotation().getRadians() + value));
42+
}
43+
};
44+
45+
/** An arguments provider for Pose3dComponent values that represent translations. */
46+
static class TranslationsArgumentsProvider extends ComponentArgumentsProvider<Pose2dComponent> {
47+
TranslationsArgumentsProvider() {
48+
super(Type.TRANSLATION, Stream.of(Pose2dComponent.values()));
49+
}
50+
}
51+
52+
private final Type componentType;
53+
54+
Pose2dComponent(Type componentType) {
55+
this.componentType = componentType;
56+
}
57+
58+
@Override
59+
public final Type getType() {
60+
return componentType;
61+
}
62+
63+
abstract Pose2d add(Pose2d pose, double value);
64+
65+
final Translation2d add(Translation2d translation, double value) {
66+
Pose2d pose = new Pose2d(translation, Rotation2d.kZero);
67+
pose = add(pose, value);
68+
return pose.getTranslation();
69+
}
70+
71+
final Rotation2d add(Rotation2d rotation, double value) {
72+
Pose2d pose = new Pose2d(Translation2d.kZero, rotation);
73+
pose = add(pose, value);
74+
return pose.getRotation();
75+
}
76+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import static org.junit.jupiter.api.Assertions.assertThrows;
19+
20+
import edu.wpi.first.math.geometry.Pose2d;
21+
import edu.wpi.first.math.geometry.Rotation2d;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.EnumSource;
24+
25+
/** Tests for {@link Pose2dSubject}. */
26+
class Pose2dSubjectTest {
27+
private static final Pose2d POSE = new Pose2d(7.353, 0.706, new Rotation2d(Math.PI / 6));
28+
29+
@ParameterizedTest
30+
@EnumSource(Pose2dComponent.class)
31+
public void isWithin_valueWithinTolerance_doesNotThrow(Pose2dComponent component) {
32+
Pose2d closePose = component.add(POSE, 0.009);
33+
34+
Pose2dSubject.assertThat(closePose).isWithin(0.01).of(POSE);
35+
}
36+
37+
@ParameterizedTest
38+
@EnumSource(Pose2dComponent.class)
39+
public void isWithin_valueNotWithinTolerance_throws(Pose2dComponent component) {
40+
Pose2d closePose = component.add(POSE, 0.011);
41+
42+
assertThrows(
43+
AssertionError.class, () -> Pose2dSubject.assertThat(closePose).isWithin(0.01).of(POSE));
44+
}
45+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import edu.wpi.first.math.geometry.Pose3d;
19+
import edu.wpi.first.math.geometry.Rotation3d;
20+
import edu.wpi.first.math.geometry.Translation3d;
21+
import java.util.stream.Stream;
22+
23+
/** Represents component in a three-dimensional coordinate system. */
24+
enum Pose3dComponent implements Component {
25+
X(Type.TRANSLATION) {
26+
@Override
27+
Pose3d add(Pose3d pose, double value) {
28+
return new Pose3d(pose.getX() + value, pose.getY(), pose.getZ(), pose.getRotation());
29+
}
30+
},
31+
Y(Type.TRANSLATION) {
32+
@Override
33+
Pose3d add(Pose3d pose, double value) {
34+
return new Pose3d(pose.getX(), pose.getY() + value, pose.getZ(), pose.getRotation());
35+
}
36+
},
37+
Z(Type.TRANSLATION) {
38+
@Override
39+
Pose3d add(Pose3d pose, double value) {
40+
return new Pose3d(pose.getX(), pose.getY(), pose.getZ() + value, pose.getRotation());
41+
}
42+
},
43+
ROLL(Type.ROTATION) {
44+
@Override
45+
Pose3d add(Pose3d pose, double value) {
46+
Rotation3d rotation = pose.getRotation();
47+
return new Pose3d(
48+
pose.getTranslation(),
49+
new Rotation3d(rotation.getX() + value, rotation.getY(), rotation.getZ()));
50+
}
51+
},
52+
PITCH(Type.ROTATION) {
53+
@Override
54+
Pose3d add(Pose3d pose, double value) {
55+
Rotation3d rotation = pose.getRotation();
56+
return new Pose3d(
57+
pose.getTranslation(),
58+
new Rotation3d(rotation.getX(), rotation.getY() + value, rotation.getZ()));
59+
}
60+
},
61+
YAW(Type.ROTATION) {
62+
@Override
63+
Pose3d add(Pose3d pose, double value) {
64+
Rotation3d rotation = pose.getRotation();
65+
return new Pose3d(
66+
pose.getTranslation(),
67+
new Rotation3d(rotation.getX(), rotation.getY(), rotation.getZ() + value));
68+
}
69+
};
70+
71+
/** An arguments provider for Pose3dComponent values that represent translations. */
72+
static class TranslationsArgumentsProvider extends ComponentArgumentsProvider<Pose3dComponent> {
73+
TranslationsArgumentsProvider() {
74+
super(Type.TRANSLATION, Stream.of(Pose3dComponent.values()));
75+
}
76+
}
77+
78+
/** An arguments provider for Pose3dComponent values that represent rotations. */
79+
static class RotationsArgumentsProvider extends ComponentArgumentsProvider<Pose3dComponent> {
80+
RotationsArgumentsProvider() {
81+
super(Type.ROTATION, Stream.of(Pose3dComponent.values()));
82+
}
83+
}
84+
85+
private final Type componentType;
86+
87+
Pose3dComponent(Type componentType) {
88+
this.componentType = componentType;
89+
}
90+
91+
@Override
92+
public final Type getType() {
93+
return componentType;
94+
}
95+
96+
abstract Pose3d add(Pose3d pose, double value);
97+
98+
final Translation3d add(Translation3d translation, double value) {
99+
Pose3d pose = new Pose3d(translation, Rotation3d.kZero);
100+
pose = add(pose, value);
101+
return pose.getTranslation();
102+
}
103+
104+
final Rotation3d add(Rotation3d rotation, double value) {
105+
Pose3d pose = new Pose3d(Translation3d.kZero, rotation);
106+
pose = add(pose, value);
107+
return pose.getRotation();
108+
}
109+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import static org.junit.jupiter.api.Assertions.*;
19+
20+
import edu.wpi.first.math.geometry.Pose3d;
21+
import edu.wpi.first.math.geometry.Rotation3d;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.EnumSource;
24+
25+
/** Tests for {@link Pose3dSubject}. */
26+
class Pose3dSubjectTest {
27+
private static final Pose3d POSE =
28+
new Pose3d(7.353, 0.706, 42.00, new Rotation3d(6.81, -25.67, 3.16));
29+
30+
@ParameterizedTest
31+
@EnumSource(Pose3dComponent.class)
32+
public void isWithin_valueWithinTolerance_doesNotThrow(Pose3dComponent component) {
33+
Pose3d closePose = component.add(POSE, 0.009);
34+
35+
Pose3dSubject.assertThat(closePose).isWithin(0.01).of(POSE);
36+
}
37+
38+
@ParameterizedTest
39+
@EnumSource(Pose3dComponent.class)
40+
public void isWithin_valueNotWithinTolerance_throws(Pose3dComponent component) {
41+
Pose3d closePose = component.add(POSE, 0.011);
42+
43+
assertThrows(
44+
AssertionError.class, () -> Pose3dSubject.assertThat(closePose).isWithin(0.01).of(POSE));
45+
}
46+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2026 Prospect Robotics SWENext Club
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.team2813.lib2813.testing.truth;
17+
18+
import static org.junit.jupiter.api.Assertions.*;
19+
20+
import edu.wpi.first.math.geometry.Rotation2d;
21+
import org.junit.jupiter.api.Test;
22+
23+
/** Tests for {@link Rotation2dSubject}. */
24+
class Rotation2dSubjectTest {
25+
private static final Rotation2d ROTATION = new Rotation2d(Math.PI / 6);
26+
27+
@Test
28+
public void isWithin_valueWithinTolerance_doesNotThrow() {
29+
Rotation2d closeRotation = Pose2dComponent.R.add(ROTATION, 0.009);
30+
31+
Rotation2dSubject.assertThat(closeRotation).isWithin(0.01).of(ROTATION);
32+
}
33+
34+
@Test
35+
public void isWithin_valueNotWithinTolerance_throws() {
36+
Rotation2d closeRotation = Pose2dComponent.R.add(ROTATION, 0.011);
37+
38+
assertThrows(
39+
AssertionError.class,
40+
() -> Rotation2dSubject.assertThat(closeRotation).isWithin(0.01).of(ROTATION));
41+
}
42+
}

0 commit comments

Comments
 (0)