diff --git a/src/software/ai/hl/stp/play/BUILD b/src/software/ai/hl/stp/play/BUILD index db672cbc01..a3deeb5167 100644 --- a/src/software/ai/hl/stp/play/BUILD +++ b/src/software/ai/hl/stp/play/BUILD @@ -169,7 +169,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) @@ -214,7 +214,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) @@ -270,7 +270,7 @@ py_test( "//proto:software_py_proto", "//proto:tbots_py_proto", "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/ball_placement/BUILD b/src/software/ai/hl/stp/play/ball_placement/BUILD index c59998362e..219650ea12 100644 --- a/src/software/ai/hl/stp/play/ball_placement/BUILD +++ b/src/software/ai/hl/stp/play/ball_placement/BUILD @@ -40,7 +40,7 @@ py_test( tags = ["exclusive"], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/ball_placement/ball_placement_play_test.py b/src/software/ai/hl/stp/play/ball_placement/ball_placement_play_test.py index 82bb5bb25e..fbb09deebc 100644 --- a/src/software/ai/hl/stp/play/ball_placement/ball_placement_play_test.py +++ b/src/software/ai/hl/stp/play/ball_placement/ball_placement_play_test.py @@ -5,11 +5,13 @@ from proto.import_all_protos import * from proto.ssl_gc_common_pb2 import Team from proto.message_translation.tbots_protobuf import create_world_state -from software.simulated_tests.ball_enters_region import ( +from software.simulated_tests.pytest_validations.ball_enters_region import ( BallAlwaysStaysInRegion, BallEventuallyEntersRegion, ) -from software.simulated_tests.robot_enters_region import RobotEventuallyExitsRegion +from software.simulated_tests.pytest_validations.robot_enters_region import ( + RobotEventuallyExitsRegion, +) from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/hl/stp/play/crease_defense/BUILD b/src/software/ai/hl/stp/play/crease_defense/BUILD index f166ec7122..bb6402127a 100644 --- a/src/software/ai/hl/stp/play/crease_defense/BUILD +++ b/src/software/ai/hl/stp/play/crease_defense/BUILD @@ -39,7 +39,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/defense/BUILD b/src/software/ai/hl/stp/play/defense/BUILD index ea875f597c..012f16b25c 100644 --- a/src/software/ai/hl/stp/play/defense/BUILD +++ b/src/software/ai/hl/stp/play/defense/BUILD @@ -42,7 +42,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/defense/defense_play_test.py b/src/software/ai/hl/stp/play/defense/defense_play_test.py index ba4ab7a8f1..4fdeab5419 100644 --- a/src/software/ai/hl/stp/play/defense/defense_play_test.py +++ b/src/software/ai/hl/stp/play/defense/defense_play_test.py @@ -2,8 +2,8 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.friendly_has_ball_possession import ( +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import ( FriendlyEventuallyHasBallPossession, ) from proto.message_translation.tbots_protobuf import create_world_state diff --git a/src/software/ai/hl/stp/play/enemy_ball_placement/BUILD b/src/software/ai/hl/stp/play/enemy_ball_placement/BUILD index e8a02bfdc6..c76845ca98 100644 --- a/src/software/ai/hl/stp/play/enemy_ball_placement/BUILD +++ b/src/software/ai/hl/stp/play/enemy_ball_placement/BUILD @@ -31,7 +31,7 @@ py_test( tags = ["exclusive"], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/enemy_ball_placement/enemy_ball_placement_play_test.py b/src/software/ai/hl/stp/play/enemy_ball_placement/enemy_ball_placement_play_test.py index f6515ae3a0..01cb4f16cd 100644 --- a/src/software/ai/hl/stp/play/enemy_ball_placement/enemy_ball_placement_play_test.py +++ b/src/software/ai/hl/stp/play/enemy_ball_placement/enemy_ball_placement_play_test.py @@ -2,7 +2,7 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName -from software.simulated_tests.robot_enters_placement_region import * +from software.simulated_tests.pytest_validations.robot_enters_placement_region import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/hl/stp/play/enemy_free_kick/BUILD b/src/software/ai/hl/stp/play/enemy_free_kick/BUILD index 2e6193787a..c538123c6e 100644 --- a/src/software/ai/hl/stp/play/enemy_free_kick/BUILD +++ b/src/software/ai/hl/stp/play/enemy_free_kick/BUILD @@ -45,7 +45,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/enemy_free_kick/enemy_free_kick_play_test.py b/src/software/ai/hl/stp/play/enemy_free_kick/enemy_free_kick_play_test.py index 2a389e2bad..ccab4d5d37 100644 --- a/src/software/ai/hl/stp/play/enemy_free_kick/enemy_free_kick_play_test.py +++ b/src/software/ai/hl/stp/play/enemy_free_kick/enemy_free_kick_play_test.py @@ -3,14 +3,11 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName -from software.simulated_tests.or_validation import OrValidation +from software.simulated_tests.pytest_validations.or_validation import OrValidation -from software.simulated_tests.ball_moves_from_rest import ( - BallEventuallyMovesFromRest, -) -from software.simulated_tests.friendly_team_scored import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.robot_enters_region import ( +from software.simulated_tests.pytest_validations.friendly_team_scored import * +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.robot_enters_region import ( RobotEventuallyEntersRegion, RobotNeverEntersRegion, ) @@ -136,11 +133,14 @@ def setup(*args): RobotNeverEntersRegion( regions=[tbots_cpp.Circle(ball_initial_pos, 0.05)] ), - BallEventuallyMovesFromRest(position=ball_initial_pos), + BallEventuallyExitsRegion( + regions=[tbots_cpp.Circle(ball_initial_pos, 0.05)] + ), ] ) ] ] + # Eventually Validation eventually_validation_sequence_set = [ [RobotEventuallyEntersRegion(regions=[tbots_cpp.Circle(ball_initial_pos, 1)])] diff --git a/src/software/ai/hl/stp/play/example/BUILD b/src/software/ai/hl/stp/play/example/BUILD index faa3db67d5..b3ff15e029 100644 --- a/src/software/ai/hl/stp/play/example/BUILD +++ b/src/software/ai/hl/stp/play/example/BUILD @@ -56,8 +56,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/example/example_play_test.py b/src/software/ai/hl/stp/play/example/example_play_test.py index 31f5ca4536..20ab8c1e07 100644 --- a/src/software/ai/hl/stp/play/example/example_play_test.py +++ b/src/software/ai/hl/stp/play/example/example_play_test.py @@ -1,9 +1,9 @@ import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_enters_region import ( +from software.simulated_tests.pytest_validations.robot_enters_region import ( NumberOfRobotsEventuallyExitsRegion, NumberOfRobotsEventuallyEntersRegion, ) -from software.simulated_tests.robot_speed_threshold import * +from software.simulated_tests.pytest_validations.robot_speed_threshold import * from proto.message_translation.tbots_protobuf import create_world_state from proto.ssl_gc_common_pb2 import Team from proto.play_pb2 import Play, PlayName diff --git a/src/software/ai/hl/stp/play/free_kick/BUILD b/src/software/ai/hl/stp/play/free_kick/BUILD index df9375a693..88815024af 100644 --- a/src/software/ai/hl/stp/play/free_kick/BUILD +++ b/src/software/ai/hl/stp/play/free_kick/BUILD @@ -54,7 +54,7 @@ py_test( tags = ["exclusive"], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/free_kick/free_kick_play_test.py b/src/software/ai/hl/stp/play/free_kick/free_kick_play_test.py index c3636d1418..4bc30bd442 100644 --- a/src/software/ai/hl/stp/play/free_kick/free_kick_play_test.py +++ b/src/software/ai/hl/stp/play/free_kick/free_kick_play_test.py @@ -1,11 +1,12 @@ import pytest - import software.python_bindings as tbots_cpp + +from proto.import_all_protos import * + from proto.play_pb2 import Play, PlayName -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.friendly_team_scored import * -from proto.message_translation.tbots_protobuf import create_world_state from proto.ssl_gc_common_pb2 import Team + +from proto.message_translation.tbots_protobuf import create_world_state from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/hl/stp/play/halt_play/BUILD b/src/software/ai/hl/stp/play/halt_play/BUILD index a491d9dcb6..d76695e405 100644 --- a/src/software/ai/hl/stp/play/halt_play/BUILD +++ b/src/software/ai/hl/stp/play/halt_play/BUILD @@ -43,8 +43,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/halt_play/halt_play_test.py b/src/software/ai/hl/stp/play/halt_play/halt_play_test.py index b55f213633..a6ce7d2f5c 100644 --- a/src/software/ai/hl/stp/play/halt_play/halt_play_test.py +++ b/src/software/ai/hl/stp/play/halt_play/halt_play_test.py @@ -1,5 +1,5 @@ import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_speed_threshold import * +from software.simulated_tests.pytest_validations.robot_speed_threshold import * from proto.message_translation.tbots_protobuf import create_world_state from proto.ssl_gc_common_pb2 import Team from software.simulated_tests.simulated_test_fixture import ( diff --git a/src/software/ai/hl/stp/play/kickoff_play_test.py b/src/software/ai/hl/stp/play/kickoff_play_test.py index 54d4e53be6..0d3438ef4f 100644 --- a/src/software/ai/hl/stp/play/kickoff_play_test.py +++ b/src/software/ai/hl/stp/play/kickoff_play_test.py @@ -2,16 +2,15 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName -from software.simulated_tests.robot_enters_region import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.ball_moves_from_rest import * +from software.simulated_tests.pytest_validations.robot_enters_region import * +from software.simulated_tests.pytest_validations.ball_enters_region import * from proto.import_all_protos import * from proto.message_translation.tbots_protobuf import create_world_state from proto.ssl_gc_common_pb2 import Team from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) -from software.simulated_tests.or_validation import OrValidation +from software.simulated_tests.pytest_validations.or_validation import OrValidation @pytest.mark.parametrize("is_friendly_test", [True, False]) @@ -80,8 +79,8 @@ def setup(*args): # Always Validation always_validation_sequence_set = [[]] - ball_moves_at_rest_validation = BallAlwaysMovesFromRest( - position=tbots_cpp.Point(0, 0), threshold=0.05 + ball_moves_at_rest_validation = BallNeverEntersRegion( + regions=[tbots_cpp.Circle(tbots_cpp.Point(0, 0), 0.05)] ) expected_center_circle_or_validation_set = [ diff --git a/src/software/ai/hl/stp/play/offense/BUILD b/src/software/ai/hl/stp/play/offense/BUILD index 4e2658fa63..b01c38acad 100644 --- a/src/software/ai/hl/stp/play/offense/BUILD +++ b/src/software/ai/hl/stp/play/offense/BUILD @@ -39,7 +39,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/play/offense/offense_play_test.py b/src/software/ai/hl/stp/play/offense/offense_play_test.py index 34b14604d1..a9b17ee3ff 100644 --- a/src/software/ai/hl/stp/play/offense/offense_play_test.py +++ b/src/software/ai/hl/stp/play/offense/offense_play_test.py @@ -1,10 +1,9 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName - -from software.simulated_tests.excessive_dribbling import NeverExcessivelyDribbles -from software.simulated_tests.friendly_team_scored import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.friendly_has_ball_possession import * +from software.simulated_tests.pytest_validations.friendly_team_scored import * +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import * +from software.simulated_tests.pytest_validations.excessive_dribbling import * from proto.message_translation.tbots_protobuf import create_world_state from proto.ssl_gc_common_pb2 import Team from software.simulated_tests.simulated_test_fixture import ( diff --git a/src/software/ai/hl/stp/play/passing_sim_test.py b/src/software/ai/hl/stp/play/passing_sim_test.py index 90522c10d5..e1d47514f1 100644 --- a/src/software/ai/hl/stp/play/passing_sim_test.py +++ b/src/software/ai/hl/stp/play/passing_sim_test.py @@ -1,19 +1,21 @@ import pytest -import math import software.python_bindings as tbots_cpp +import math from proto.import_all_protos import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) from proto.message_translation.tbots_protobuf import create_world_state -from software.simulated_tests.friendly_receives_ball_slow import ( +from software.simulated_tests.pytest_validations.friendly_receives_ball_slow import ( FriendlyAlwaysReceivesBallSlow, ) -from software.simulated_tests.friendly_has_ball_possession import ( +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import ( FriendlyEventuallyHasBallPossession, ) -from software.simulated_tests.ball_moves_in_direction import BallMovesForwardInRegions -from software.simulated_tests.ball_enters_region import ( +from software.simulated_tests.pytest_validations.ball_moves_in_direction import ( + BallMovesForwardInRegions, +) +from software.simulated_tests.pytest_validations.ball_enters_region import ( BallEventuallyExitsRegion, BallEventuallyEntersRegion, ) diff --git a/src/software/ai/hl/stp/play/shoot_or_chip_play_test.py b/src/software/ai/hl/stp/play/shoot_or_chip_play_test.py index b6b59307dc..5584002067 100644 --- a/src/software/ai/hl/stp/play/shoot_or_chip_play_test.py +++ b/src/software/ai/hl/stp/play/shoot_or_chip_play_test.py @@ -3,7 +3,7 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName -from software.simulated_tests.ball_enters_region import * +from software.simulated_tests.pytest_validations.ball_enters_region import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/hl/stp/tactic/crease_defender/BUILD b/src/software/ai/hl/stp/tactic/crease_defender/BUILD index 8cabfce189..c75d4a6e30 100644 --- a/src/software/ai/hl/stp/tactic/crease_defender/BUILD +++ b/src/software/ai/hl/stp/tactic/crease_defender/BUILD @@ -59,8 +59,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic_test.py b/src/software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic_test.py index 3f17764a58..87ae78fd52 100644 --- a/src/software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic_test.py +++ b/src/software/ai/hl/stp/tactic/crease_defender/crease_defender_tactic_test.py @@ -1,18 +1,28 @@ import pytest - import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_enters_region import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.ball_moves_in_direction import * -from software.simulated_tests.friendly_has_ball_possession import * -from software.simulated_tests.ball_speed_threshold import * -from software.simulated_tests.robot_speed_threshold import * -from software.simulated_tests.excessive_dribbling import * + +from proto.import_all_protos import ( + BallStealMode, + CreaseDefenderAlignment, + CreaseDefenderTactic, + MaxAllowedSpeedMode, +) +from proto.message_translation.tbots_protobuf import create_world_state +from software.simulated_tests.pytest_validations.ball_is_off_ground import ( + BallIsAlwaysOnGround, + BallIsEventuallyOffGround, +) +from software.simulated_tests.pytest_validations.excessive_dribbling import ( + NeverExcessivelyDribbles, +) +from software.simulated_tests.pytest_validations.robot_enters_region import ( + RobotEventuallyEntersRegion, + RobotNeverEntersRegion, +) +from proto.import_all_protos import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) -from software.simulated_tests.ball_is_off_ground import * -from proto.message_translation.tbots_protobuf import create_world_state @pytest.mark.parametrize( diff --git a/src/software/ai/hl/stp/tactic/dribble/BUILD b/src/software/ai/hl/stp/tactic/dribble/BUILD index 67199a889f..6ef8439c16 100644 --- a/src/software/ai/hl/stp/tactic/dribble/BUILD +++ b/src/software/ai/hl/stp/tactic/dribble/BUILD @@ -74,8 +74,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py b/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py index 443cc06825..0e83d695ec 100644 --- a/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py +++ b/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py @@ -1,19 +1,15 @@ import pytest - import software.python_bindings as tbots_cpp -from software.simulated_tests.excessive_dribbling import ( - NeverExcessivelyDribbles, + +from proto.import_all_protos import * +from proto.message_translation.tbots_protobuf import DribbleTactic, create_world_state +from software.simulated_tests.pytest_validations.excessive_dribbling import ( EventuallyStartsExcessivelyDribbling, -) -from proto.message_translation.tbots_protobuf import ( - WorldState, - AssignedTacticPlayControlParams, - DribbleTactic, + NeverExcessivelyDribbles, ) from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) -from proto.message_translation.tbots_protobuf import create_world_state @pytest.mark.parametrize( diff --git a/src/software/ai/hl/stp/tactic/goalie/BUILD b/src/software/ai/hl/stp/tactic/goalie/BUILD index abdb4d7636..5fbd6a27c4 100644 --- a/src/software/ai/hl/stp/tactic/goalie/BUILD +++ b/src/software/ai/hl/stp/tactic/goalie/BUILD @@ -58,8 +58,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/tactic/goalie/goalie_tactic_test.py b/src/software/ai/hl/stp/tactic/goalie/goalie_tactic_test.py index c915075666..2abe55a35f 100644 --- a/src/software/ai/hl/stp/tactic/goalie/goalie_tactic_test.py +++ b/src/software/ai/hl/stp/tactic/goalie/goalie_tactic_test.py @@ -1,13 +1,14 @@ import pytest import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_enters_region import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.ball_moves_in_direction import * -from software.simulated_tests.friendly_has_ball_possession import * -from software.simulated_tests.ball_speed_threshold import * -from software.simulated_tests.robot_speed_threshold import * -from software.simulated_tests.excessive_dribbling import * +from proto.import_all_protos import GoalieTactic, MaxAllowedSpeedMode +from software.simulated_tests.pytest_validations.robot_enters_region import * +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.ball_moves_in_direction import * +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import * +from software.simulated_tests.pytest_validations.ball_speed_threshold import * +from software.simulated_tests.pytest_validations.robot_speed_threshold import * +from software.simulated_tests.pytest_validations.excessive_dribbling import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/hl/stp/tactic/pass_defender/BUILD b/src/software/ai/hl/stp/tactic/pass_defender/BUILD index e87d8f757c..31b9d28f46 100644 --- a/src/software/ai/hl/stp/tactic/pass_defender/BUILD +++ b/src/software/ai/hl/stp/tactic/pass_defender/BUILD @@ -45,8 +45,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/hl/stp/tactic/pass_defender/pass_defender_tactic_test.py b/src/software/ai/hl/stp/tactic/pass_defender/pass_defender_tactic_test.py index 5df7db7a5d..46fdefaf01 100644 --- a/src/software/ai/hl/stp/tactic/pass_defender/pass_defender_tactic_test.py +++ b/src/software/ai/hl/stp/tactic/pass_defender/pass_defender_tactic_test.py @@ -1,13 +1,14 @@ import pytest import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_enters_region import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.ball_moves_in_direction import * -from software.simulated_tests.friendly_has_ball_possession import * -from software.simulated_tests.ball_speed_threshold import * -from software.simulated_tests.robot_speed_threshold import * -from software.simulated_tests.excessive_dribbling import * +from proto.import_all_protos import PassDefenderTactic, BallStealMode +from software.simulated_tests.pytest_validations.robot_enters_region import * +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.ball_moves_in_direction import * +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import * +from software.simulated_tests.pytest_validations.ball_speed_threshold import * +from software.simulated_tests.pytest_validations.robot_speed_threshold import * +from software.simulated_tests.pytest_validations.excessive_dribbling import * from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) diff --git a/src/software/ai/navigator/trajectory/BUILD b/src/software/ai/navigator/trajectory/BUILD index e3a243f39c..667735d3dd 100644 --- a/src/software/ai/navigator/trajectory/BUILD +++ b/src/software/ai/navigator/trajectory/BUILD @@ -157,7 +157,7 @@ py_test( deps = [ "//proto/message_translation:py_tbots_protobuf", "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/ai/navigator/trajectory/simulated_hrvo_test.py b/src/software/ai/navigator/trajectory/simulated_hrvo_test.py index b88322d0ad..a2ed3b441f 100644 --- a/src/software/ai/navigator/trajectory/simulated_hrvo_test.py +++ b/src/software/ai/navigator/trajectory/simulated_hrvo_test.py @@ -2,7 +2,7 @@ from software.simulated_tests.simulated_test_fixture import ( pytest_main, ) -from software.simulated_tests.avoid_collisions import * +from software.simulated_tests.pytest_validations.avoid_collisions import * import software.python_bindings as tbots from software.py_constants import * from proto.message_translation.tbots_protobuf import create_world_state @@ -10,7 +10,7 @@ from proto.import_all_protos import * from proto.ssl_gc_common_pb2 import Team from software.simulated_tests.simulated_test_fixture import SimulatedTestRunner -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( create_validation_types, create_validation_geometry, ) diff --git a/src/software/field_tests/BUILD b/src/software/field_tests/BUILD index ad76156e99..b742fb70b5 100644 --- a/src/software/field_tests/BUILD +++ b/src/software/field_tests/BUILD @@ -16,7 +16,7 @@ py_library( "//software/networking/unix:threaded_unix_listener_py", "//software/networking/unix:threaded_unix_sender_py", "//software/simulated_tests:tbots_test_runner", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", "//software/thunderscope", "//software/thunderscope:constants", "//software/thunderscope:estop_helpers", @@ -39,7 +39,7 @@ py_test( deps = [ "//software:conftest", "//software/simulated_tests:tbots_test_runner", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) @@ -56,7 +56,7 @@ py_test( deps = [ "//software:conftest", "//software/simulated_tests:tbots_test_runner", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) @@ -68,7 +68,7 @@ py_test( ], deps = [ "//software:conftest", - "//software/simulated_tests:validation", + "//software/simulated_tests/pytest_validations:all_validations", requirement("pytest"), ], ) diff --git a/src/software/field_tests/field_test_fixture.py b/src/software/field_tests/field_test_fixture.py index 42c0c9f6ee..b8758292e7 100644 --- a/src/software/field_tests/field_test_fixture.py +++ b/src/software/field_tests/field_test_fixture.py @@ -7,7 +7,7 @@ import argparse from proto.import_all_protos import * -from software.simulated_tests import validation +from software.simulated_tests.pytest_validations import validation from software.thunderscope.constants import EstopMode, IndividualRobotMode from software.thunderscope.thunderscope import Thunderscope from software.thunderscope.proto_unix_io import ProtoUnixIO diff --git a/src/software/field_tests/passing_field_test.py b/src/software/field_tests/passing_field_test.py index 9899c6b63a..1af6b8ce29 100644 --- a/src/software/field_tests/passing_field_test.py +++ b/src/software/field_tests/passing_field_test.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * from software.field_tests.field_test_fixture import * -from software.simulated_tests.friendly_receives_ball_slow import ( +from software.simulated_tests.pytest_validations.friendly_receives_ball_slow import ( FriendlyAlwaysReceivesBallSlow, ) from software.simulated_tests.simulated_test_fixture import ( diff --git a/src/software/simulated_tests/BUILD b/src/software/simulated_tests/BUILD index 2b33a53da5..7f8ad64dca 100644 --- a/src/software/simulated_tests/BUILD +++ b/src/software/simulated_tests/BUILD @@ -9,23 +9,53 @@ compile_pip_requirements( requirements_txt = "requirements_lock.txt", ) -py_test( - name = "simulated_test_ball_model", +py_library( + name = "tbots_test_runner", srcs = [ - "simulated_test_ball_model.py", + "tbots_test_runner.py", ], - # TODO (#2619) Remove tag to run in parallel - tags = [ - "exclusive", + data = [ + "//software:py_constants.so", ], deps = [ - "//software:conftest", - "//software/simulated_tests:speed_threshold_helpers", - "//software/simulated_tests:validation", - requirement("pytest"), + "//proto:import_all_protos", + "//software/logger:py_logger", + "//software/networking/unix:threaded_unix_listener_py", + "//software/networking/unix:threaded_unix_sender_py", + "//software/simulated_tests/pytest_validations:all_validations", + "//software/thunderscope", + "//software/thunderscope:config", + "//software/thunderscope:constants", + "//software/thunderscope:time_provider", + "//software/thunderscope/binary_context_managers:full_system", + "//software/thunderscope/binary_context_managers:game_controller", + "//software/thunderscope/binary_context_managers:simulator", + ], +) + +py_library( + name = "simulated_test_fixture", + srcs = [ + "simulated_test_fixture.py", + ], + data = [ + "//software:py_constants.so", + ], + deps = [ + ":tbots_test_runner", + "//proto:import_all_protos", + "//software/logger:py_logger", + "//software/networking/unix:threaded_unix_listener_py", + "//software/networking/unix:threaded_unix_sender_py", + "//software/simulated_tests/pytest_validations:all_validations", + "//software/thunderscope", + "//software/thunderscope/binary_context_managers:full_system", + "//software/thunderscope/binary_context_managers:game_controller", + "//software/thunderscope/binary_context_managers:simulator", ], ) +# TODO (#2581): remove cc_library( name = "simulated_er_force_sim_test_fixture", testonly = True, @@ -49,6 +79,7 @@ cc_library( ], ) +# TODO (#2581): remove cc_library( name = "simulated_er_force_sim_play_test_fixture", testonly = True, @@ -61,86 +92,18 @@ cc_library( ], ) -py_library( - name = "simulated_test_fixture", - srcs = [ - "simulated_test_fixture.py", - ], - data = [ - "//software:py_constants.so", - ], - deps = [ - ":tbots_test_runner", - "//proto:import_all_protos", - "//software/logger:py_logger", - "//software/networking/unix:threaded_unix_listener_py", - "//software/networking/unix:threaded_unix_sender_py", - "//software/simulated_tests:validation", - "//software/thunderscope", - "//software/thunderscope/binary_context_managers:full_system", - "//software/thunderscope/binary_context_managers:game_controller", - "//software/thunderscope/binary_context_managers:simulator", - ], -) - -py_library( - name = "tbots_test_runner", - srcs = [ - "tbots_test_runner.py", - ], - data = [ - "//software:py_constants.so", - ], - deps = [ - "//proto:import_all_protos", - "//software/logger:py_logger", - "//software/networking/unix:threaded_unix_listener_py", - "//software/networking/unix:threaded_unix_sender_py", - "//software/simulated_tests:validation", - "//software/thunderscope", - "//software/thunderscope:config", - "//software/thunderscope:constants", - "//software/thunderscope:time_provider", - "//software/thunderscope/binary_context_managers:full_system", - "//software/thunderscope/binary_context_managers:game_controller", - "//software/thunderscope/binary_context_managers:simulator", - ], -) - -py_library( - name = "validation", +py_test( + name = "simulated_test_ball_model", srcs = [ - "avoid_collisions.py", - "ball_enters_region.py", - "ball_is_off_ground.py", - "ball_moves_forward.py", - "ball_moves_from_rest.py", - "ball_moves_in_direction.py", - "ball_speed_threshold.py", - "ball_stops_in_region.py", - "excessive_dribbling.py", - "friendly_has_ball_possession.py", - "friendly_receives_ball_slow.py", - "friendly_team_scored.py", - "or_validation.py", - "robot_enters_placement_region.py", - "robot_enters_region.py", - "robot_enters_region_and_stops.py", - "robot_speed_threshold.py", - "validation.py", + "simulated_test_ball_model.py", ], - data = [ - "//software:py_constants.so", - "//software:python_bindings.so", + # TODO (#2619) Remove tag to run in parallel + tags = [ + "exclusive", ], deps = [ - "//proto:software_py_proto", - "//proto:tbots_py_proto", - "//software/logger:py_logger", + "//software:conftest", + "//software/simulated_tests/pytest_validations:all_validations", + requirement("pytest"), ], ) - -py_library( - name = "speed_threshold_helpers", - srcs = ["speed_threshold_helpers.py"], -) diff --git a/src/software/simulated_tests/ball_moves_forward.py b/src/software/simulated_tests/ball_moves_forward.py deleted file mode 100644 index 258b9db3bd..0000000000 --- a/src/software/simulated_tests/ball_moves_forward.py +++ /dev/null @@ -1,64 +0,0 @@ -import software.python_bindings as tbots_cpp -from proto.import_all_protos import * - -from software.simulated_tests.validation import ( - Validation, - create_validation_geometry, - create_validation_types, -) -from typing import override - - -class BallMovesForward(Validation): - """Checks if ball is moving forward, i.e. in the +x direction""" - - def __init__(self, initial_ball_position): - self.last_ball_position = initial_ball_position - - @override - def get_validation_status(self, world) -> ValidationStatus: - """Checks if ball is moving forward, i.e. in the +x direction - - :param world: The world msg to validate - :return: FAILING if ball doesn't move forward - PASSING if ball moves forward - """ - validation_status = ValidationStatus.FAILING - current_ball_position = tbots_cpp.createPoint( - world.ball.current_state.global_position - ) - - if current_ball_position.x() > self.last_ball_position.x(): - validation_status = ValidationStatus.PASSING - self.last_ball_position = current_ball_position - return validation_status - - @override - def get_validation_geometry(self, world) -> ValidationGeometry: - """(override) Shows the last ball position line""" - return create_validation_geometry( - [ - tbots_cpp.Rectangle( - tbots_cpp.Point( - self.last_ball_position.x(), - tbots_cpp.Field(world.field).fieldBoundary().yMin(), - ), - tbots_cpp.Point( - self.last_ball_position.x() + 0.01, - tbots_cpp.Field(world.field).fieldBoundary().yMax(), - ), - ) - ] - ) - - @override - def __repr__(self): - return "Check that the ball moves forward" - - -( - BallEventuallyMovesForward, - BallStopsMovingForward, - BallAlwaysMovesForward, - BallNeverMovesForward, -) = create_validation_types(BallMovesForward) diff --git a/src/software/simulated_tests/ball_moves_from_rest.py b/src/software/simulated_tests/ball_moves_from_rest.py deleted file mode 100644 index 11f182af15..0000000000 --- a/src/software/simulated_tests/ball_moves_from_rest.py +++ /dev/null @@ -1,61 +0,0 @@ -import software.python_bindings as tbots_cpp -from proto.import_all_protos import * - -from software.simulated_tests.validation import ( - Validation, - create_validation_geometry, - create_validation_types, -) -from typing import override - - -class BallMovesFromRest(Validation): - """Checks if ball has moved threshold meters from initial position""" - - def __init__(self, position, threshold=0.05): - """Constructor - - :param position: initial position of the ball - :param threshold: distance for which ball is considered to have moved - """ - self.initial_ball_position = position - self.threshold = threshold - - @override - def get_validation_status(self, world) -> ValidationStatus: - """Checks if ball has moved threshold meters from initial position. Default is 0.05m. - - :param world: The world msg to validate - :return: FAILING if ball doesn't move according to RoboCup rules - PASSING if ball moves according to RoboCup rules - """ - validation_status = ValidationStatus.FAILING - current_ball_position = tbots_cpp.createPoint( - world.ball.current_state.global_position - ) - - if ( - self.initial_ball_position - current_ball_position - ).length() > self.threshold: - validation_status = ValidationStatus.PASSING - - return validation_status - - @override - def get_validation_geometry(self, world) -> ValidationGeometry: - """(override) Shows the last ball position line""" - return create_validation_geometry( - [tbots_cpp.Circle(self.initial_ball_position, self.threshold)] - ) - - @override - def __repr__(self): - return "Check that the ball moves from rest" - - -( - BallEventuallyMovesFromRest, - BallStopsMovingFromRest, - BallAlwaysMovesFromRest, - BallNeverMovesFromRest, -) = create_validation_types(BallMovesFromRest) diff --git a/src/software/simulated_tests/pytest_validations/BUILD b/src/software/simulated_tests/pytest_validations/BUILD new file mode 100644 index 0000000000..0730d966b2 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/BUILD @@ -0,0 +1,39 @@ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "all_validations", + srcs = [ + "avoid_collisions.py", + "ball_enters_region.py", + "ball_is_off_ground.py", + "ball_kicked_in_direction.py", + "ball_moves_in_direction.py", + "ball_speed_threshold.py", + "ball_stops_in_region.py", + "delay_validation.py", + "excessive_dribbling.py", + "friendly_has_ball_possession.py", + "friendly_receives_ball_slow.py", + "friendly_team_scored.py", + "or_validation.py", + "robot_at_angular_velocity.py", + "robot_at_orientation.py", + "robot_at_position.py", + "robot_enters_placement_region.py", + "robot_enters_region.py", + "robot_enters_region_and_stops.py", + "robot_received_ball.py", + "robot_speed_threshold.py", + "speed_threshold_helpers.py", + "validation.py", + ], + data = [ + "//software:py_constants.so", + "//software:python_bindings.so", + ], + deps = [ + "//proto:software_py_proto", + "//proto:tbots_py_proto", + "//software/logger:py_logger", + ], +) diff --git a/src/software/simulated_tests/pytest_validations/__init__.py b/src/software/simulated_tests/pytest_validations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/software/simulated_tests/avoid_collisions.py b/src/software/simulated_tests/pytest_validations/avoid_collisions.py similarity index 98% rename from src/software/simulated_tests/avoid_collisions.py rename to src/software/simulated_tests/pytest_validations/avoid_collisions.py index 28571474d4..9c057a23f0 100644 --- a/src/software/simulated_tests/avoid_collisions.py +++ b/src/software/simulated_tests/pytest_validations/avoid_collisions.py @@ -1,7 +1,7 @@ from software.py_constants import * import software.python_bindings as tbots from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_types, create_validation_geometry, diff --git a/src/software/simulated_tests/ball_enters_region.py b/src/software/simulated_tests/pytest_validations/ball_enters_region.py similarity index 96% rename from src/software/simulated_tests/ball_enters_region.py rename to src/software/simulated_tests/pytest_validations/ball_enters_region.py index 78c12c7895..3ba8310858 100644 --- a/src/software/simulated_tests/ball_enters_region.py +++ b/src/software/simulated_tests/pytest_validations/ball_enters_region.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/ball_is_off_ground.py b/src/software/simulated_tests/pytest_validations/ball_is_off_ground.py similarity index 97% rename from src/software/simulated_tests/ball_is_off_ground.py rename to src/software/simulated_tests/pytest_validations/ball_is_off_ground.py index 35b5b5b514..9272dcfc82 100644 --- a/src/software/simulated_tests/ball_is_off_ground.py +++ b/src/software/simulated_tests/pytest_validations/ball_is_off_ground.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/pytest_validations/ball_kicked_in_direction.py b/src/software/simulated_tests/pytest_validations/ball_kicked_in_direction.py new file mode 100644 index 0000000000..1d01f72309 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/ball_kicked_in_direction.py @@ -0,0 +1,70 @@ +import software.python_bindings as tbots_cpp +from proto.import_all_protos import * + +from software.simulated_tests.pytest_validations.validation import ( + Validation, + create_validation_geometry, + create_validation_types, +) +from typing import override + + +class BallKickedInDirection(Validation): + """Checks if the ball has been kicked in a specific direction""" + + LINE_LENGTH = 0.5 + + def __init__( + self, + kick_direction, + ): + """Constructs the validation object + + :param kick_direction: The expected direction the ball should be kicked (tbots_cpp.Angle) + """ + self.kick_direction = kick_direction + + @override + def get_validation_status(self, world) -> ValidationStatus: + """Checks if the ball has been kicked in the expected direction + + :param world: The world msg to validate + :return: FAILING if the ball has not been kicked in the expected direction + PASSING if the ball has been kicked in the expected direction + """ + # Convert ball proto to tbots_cpp ball + ball_pos = tbots_cpp.createPoint(world.ball.current_state.global_position) + ball_vel = tbots_cpp.createVector(world.ball.current_state.global_velocity) + + ball = tbots_cpp.Ball(ball_pos, ball_vel, tbots_cpp.Timestamp()) + + return ( + ValidationStatus.PASSING + if ball.hasBallBeenKicked(self.kick_direction) + else ValidationStatus.FAILING + ) + + @override + def get_validation_geometry(self, world) -> ValidationGeometry: + """Returns arrow geometry showing the expected kick direction + + :param world: The world msg to create validation geometry from + :return: ValidationGeometry containing an arrow in the kick direction + """ + ball_pos = world.ball.current_state.global_position + start = tbots_cpp.Point(ball_pos.x_meters, ball_pos.y_meters) + direction = tbots_cpp.Vector(1, 0).rotate(self.kick_direction) + end = start + direction * self.LINE_LENGTH + return create_validation_geometry([tbots_cpp.Segment(start, end)]) + + @override + def __repr__(self): + return f"Check that the ball is kicked in direction {self.kick_direction}" + + +( + BallEventuallyKickedInDirection, + _BallEventuallyNotKickedInDirection, # Doesn't make sense + _BallAlwaysKickedInDirection, # Doesn't make sense + BallNeverKickedInDirection, +) = create_validation_types(BallKickedInDirection) diff --git a/src/software/simulated_tests/ball_moves_in_direction.py b/src/software/simulated_tests/pytest_validations/ball_moves_in_direction.py similarity index 98% rename from src/software/simulated_tests/ball_moves_in_direction.py rename to src/software/simulated_tests/pytest_validations/ball_moves_in_direction.py index dff5046cd5..c85d278333 100644 --- a/src/software/simulated_tests/ball_moves_in_direction.py +++ b/src/software/simulated_tests/pytest_validations/ball_moves_in_direction.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/ball_speed_threshold.py b/src/software/simulated_tests/pytest_validations/ball_speed_threshold.py similarity index 94% rename from src/software/simulated_tests/ball_speed_threshold.py rename to src/software/simulated_tests/pytest_validations/ball_speed_threshold.py index 3fc61aecdb..b57cbf28b3 100644 --- a/src/software/simulated_tests/ball_speed_threshold.py +++ b/src/software/simulated_tests/pytest_validations/ball_speed_threshold.py @@ -1,9 +1,9 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * from software.py_constants import * -from software.simulated_tests.speed_threshold_helpers import * +from software.simulated_tests.pytest_validations.speed_threshold_helpers import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/ball_stops_in_region.py b/src/software/simulated_tests/pytest_validations/ball_stops_in_region.py similarity index 96% rename from src/software/simulated_tests/ball_stops_in_region.py rename to src/software/simulated_tests/pytest_validations/ball_stops_in_region.py index 369a1a70de..331e7f2f78 100644 --- a/src/software/simulated_tests/ball_stops_in_region.py +++ b/src/software/simulated_tests/pytest_validations/ball_stops_in_region.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/pytest_validations/delay_validation.py b/src/software/simulated_tests/pytest_validations/delay_validation.py new file mode 100644 index 0000000000..d09d25c877 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/delay_validation.py @@ -0,0 +1,51 @@ +from typing import override + +from proto.validation_pb2 import ValidationStatus, ValidationType + +from software.simulated_tests.pytest_validations.validation import ( + Validation, +) + + +class DelayValidation(Validation): + def __init__(self, delay_s, validation): + """A validation wrapper that adds a delay to given validation before being evaluated""" + # TODO: resolve difference in world proto time (real time) and simulated time + tick_duration_s = 0.0166 + + self.delay_s = delay_s + self.ticks_so_far = 0 + self.delay_ticks = int(delay_s / tick_duration_s) + self.validation = validation + # self.first_time_check = None + + @override + def get_validation_status(self, world): + # if not self.first_time_check: + # self.first_time_check = world.time_sent.epoch_timestamp_seconds + + # if ( + # world.time_sent.epoch_timestamp_seconds - self.first_time_check + # > self.delay_s + # ): + self.ticks_so_far += 1 + if self.ticks_so_far > self.delay_ticks: + return self.validation.get_validation_status(world) + else: + return ( + ValidationStatus.PASSING + if self.validation.get_validation_type() == ValidationType.ALWAYS + else ValidationStatus.FAILING + ) + + @override + def get_validation_geometry(self, world): + return self.validation.get_validation_geometry(world) + + @override + def __repr__(self): + return f"Delayed validation after {self.delay_s} seconds for {self.validation.__repr__()}" + + @override + def get_validation_type(self, world): + return self.validation.get_validation_type() diff --git a/src/software/simulated_tests/excessive_dribbling.py b/src/software/simulated_tests/pytest_validations/excessive_dribbling.py similarity index 97% rename from src/software/simulated_tests/excessive_dribbling.py rename to src/software/simulated_tests/pytest_validations/excessive_dribbling.py index b62045bb7c..9367874521 100644 --- a/src/software/simulated_tests/excessive_dribbling.py +++ b/src/software/simulated_tests/pytest_validations/excessive_dribbling.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import ValidationStatus, ValidationGeometry -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/friendly_has_ball_possession.py b/src/software/simulated_tests/pytest_validations/friendly_has_ball_possession.py similarity index 96% rename from src/software/simulated_tests/friendly_has_ball_possession.py rename to src/software/simulated_tests/pytest_validations/friendly_has_ball_possession.py index b63e4104fb..4af8c8da20 100644 --- a/src/software/simulated_tests/friendly_has_ball_possession.py +++ b/src/software/simulated_tests/pytest_validations/friendly_has_ball_possession.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/friendly_receives_ball_slow.py b/src/software/simulated_tests/pytest_validations/friendly_receives_ball_slow.py similarity index 97% rename from src/software/simulated_tests/friendly_receives_ball_slow.py rename to src/software/simulated_tests/pytest_validations/friendly_receives_ball_slow.py index 9b5b257ed1..e086a44296 100644 --- a/src/software/simulated_tests/friendly_receives_ball_slow.py +++ b/src/software/simulated_tests/pytest_validations/friendly_receives_ball_slow.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/friendly_team_scored.py b/src/software/simulated_tests/pytest_validations/friendly_team_scored.py similarity index 95% rename from src/software/simulated_tests/friendly_team_scored.py rename to src/software/simulated_tests/pytest_validations/friendly_team_scored.py index ecf68aa0d3..538485ad95 100644 --- a/src/software/simulated_tests/friendly_team_scored.py +++ b/src/software/simulated_tests/pytest_validations/friendly_team_scored.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/or_validation.py b/src/software/simulated_tests/pytest_validations/or_validation.py similarity index 96% rename from src/software/simulated_tests/or_validation.py rename to src/software/simulated_tests/pytest_validations/or_validation.py index efb96682ca..02c5259254 100644 --- a/src/software/simulated_tests/or_validation.py +++ b/src/software/simulated_tests/pytest_validations/or_validation.py @@ -1,5 +1,5 @@ from proto.validation_pb2 import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, ) from typing import override diff --git a/src/software/simulated_tests/pytest_validations/robot_at_angular_velocity.py b/src/software/simulated_tests/pytest_validations/robot_at_angular_velocity.py new file mode 100644 index 0000000000..61fbe6e808 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/robot_at_angular_velocity.py @@ -0,0 +1,66 @@ +import software.python_bindings as tbots_cpp +from proto.import_all_protos import * + +from software.simulated_tests.pytest_validations.validation import ( + Validation, + create_validation_geometry, + create_validation_types, +) +from typing import override + + +class RobotAtAngularVelocity(Validation): + """Checks if a robot is at a specific angular velocity""" + + def __init__(self, robot_id, angular_velocity, threshold=0.1): + """Constructs the validation object + + :param robot_id: The ID of the robot to check + :param angular_velocity: The expected angular velocity (tbots_cpp.Angle) + :param threshold: The tolerance in radians/s for the angular velocity check + """ + self.robot_id = robot_id + self.angular_velocity = angular_velocity + self.threshold = threshold + + @override + def get_validation_status(self, world) -> ValidationStatus: + """Checks if the robot is at the expected angular velocity + + :param world: The world msg to validate + :return: FAILING when the robot is not at the expected angular velocity + PASSING when the robot is at the expected angular velocity + """ + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + robot_ang_vel = tbots_cpp.Angle.fromRadians( + robot.current_state.global_angular_velocity.radians_per_second + ) + angle_diff = abs( + robot_ang_vel.toRadians() - self.angular_velocity.toRadians() + ) + if angle_diff < self.threshold: + return ValidationStatus.PASSING + return ValidationStatus.FAILING + + @override + def get_validation_geometry(self, world) -> ValidationGeometry: + """Returns the angular velocity of the robot for visualization + + :param world: The world msg to create validation geometry from + :return: ValidationGeometry showing the robot's angular velocity + """ + # TODO (#3637): create validation geometry + return create_validation_geometry() + + @override + def __repr__(self): + return f"Check that robot {self.robot_id} is at angular velocity {self.angular_velocity} (threshold={self.threshold})" + + +( + RobotEventuallyAtAngularVelocity, + RobotEventuallyNotAtAngularVelocity, + RobotAlwaysAtAngularVelocity, + RobotNeverAtAngularVelocity, +) = create_validation_types(RobotAtAngularVelocity) diff --git a/src/software/simulated_tests/pytest_validations/robot_at_orientation.py b/src/software/simulated_tests/pytest_validations/robot_at_orientation.py new file mode 100644 index 0000000000..752bd206e2 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/robot_at_orientation.py @@ -0,0 +1,74 @@ +import software.python_bindings as tbots_cpp +from proto.import_all_protos import * + +from software.simulated_tests.pytest_validations.validation import ( + Validation, + create_validation_geometry, + create_validation_types, +) +from typing import override + + +class RobotAtOrientation(Validation): + """Checks if a robot is at a specific orientation""" + + LINE_LENGTH = 0.3 + + def __init__(self, robot_id, orientation, threshold=0.1): + """Constructs the validation object + + :param robot_id: The ID of the robot to check + :param orientation: The expected orientation (tbots_cpp.Angle) + :param threshold: The tolerance in radians for the orientation check + """ + self.robot_id = robot_id + self.orientation = orientation + self.threshold = threshold + + @override + def get_validation_status(self, world) -> ValidationStatus: + """Checks if the robot is at the expected orientation + + :param world: The world msg to validate + :return: FAILING when the robot is not at the expected orientation + PASSING when the robot is at the expected orientation + """ + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + robot_angle = tbots_cpp.Angle.fromRadians( + robot.current_state.global_orientation.radians + ) + angle_diff = robot_angle.minDiff(self.orientation).toRadians() + if angle_diff < self.threshold: + return ValidationStatus.PASSING + return ValidationStatus.FAILING + + @override + def get_validation_geometry(self, world) -> ValidationGeometry: + """Returns the orientation of the robot for visualization + + :param world: The world msg to create validation geometry from + :return: ValidationGeometry containing the robot's orientation + """ + # TODO (#3637): create better validation geometry + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + robot_pos = tbots_cpp.createPoint(robot.current_state.global_position) + direction = tbots_cpp.Vector(1, 0).rotate(self.orientation) + end_point = robot_pos + direction * self.LINE_LENGTH + return create_validation_geometry( + [tbots_cpp.Segment(robot_pos, end_point)] + ) + return create_validation_geometry() + + @override + def __repr__(self): + return f"Check that robot {self.robot_id} is at orientation {self.orientation} (threshold={self.threshold})" + + +( + RobotEventuallyAtOrientation, + RobotEventuallyNotAtOrientation, + RobotAlwaysAtOrientation, + RobotNeverAtOrientation, +) = create_validation_types(RobotAtOrientation) diff --git a/src/software/simulated_tests/pytest_validations/robot_at_position.py b/src/software/simulated_tests/pytest_validations/robot_at_position.py new file mode 100644 index 0000000000..1a391c34b5 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/robot_at_position.py @@ -0,0 +1,63 @@ +import software.python_bindings as tbots_cpp +from proto.import_all_protos import * + +from software.simulated_tests.pytest_validations.validation import ( + Validation, + ValidationStatus, + create_validation_geometry, + create_validation_types, +) +from typing import override + + +class RobotAtPosition(Validation): + """Checks if a specific robot is at a given position within a threshold distance.""" + + def __init__( + self, robot_id: int, position: tbots_cpp.Point, threshold: float = 0.05 + ): + """Initializes the validation class with robot id, position, and threshold + + :param robot_id: the id of the robot to check + :param position: the target position the robot should be at + :param threshold: the distance threshold for the robot to be considered at position + """ + self.robot_id = robot_id + self.position = position + self.threshold = threshold + + @override + def get_validation_status(self, world) -> ValidationStatus: + """Checks if the robot is at the target position + + :param world: The world msg to validate + :returns: PASSING if the robot is at the target position within threshold + FAILING otherwise + """ + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + robot_pos = tbots_cpp.createPoint(robot.current_state.global_position) + distance = (robot_pos - self.position).length() + if distance <= self.threshold: + return ValidationStatus.PASSING + break + + return ValidationStatus.FAILING + + @override + def get_validation_geometry(self, world) -> ValidationGeometry: + """(override) shows the target position""" + circle = tbots_cpp.Circle(self.position, self.threshold) + return create_validation_geometry([circle]) + + @override + def __repr__(self): + return f"Robot {self.robot_id} at position {self.position} with threshold {self.threshold}" + + +( + RobotEventuallyAtPosition, + RobotEventuallyNotAtPosition, + RobotAlwaysAtPosition, + RobotAlwaysNotAtPosition, +) = create_validation_types(RobotAtPosition) diff --git a/src/software/simulated_tests/robot_enters_placement_region.py b/src/software/simulated_tests/pytest_validations/robot_enters_placement_region.py similarity index 97% rename from src/software/simulated_tests/robot_enters_placement_region.py rename to src/software/simulated_tests/pytest_validations/robot_enters_placement_region.py index bb23adff33..978402f149 100644 --- a/src/software/simulated_tests/robot_enters_placement_region.py +++ b/src/software/simulated_tests/pytest_validations/robot_enters_placement_region.py @@ -2,7 +2,7 @@ from software.py_constants import ENEMY_BALL_PLACEMENT_DISTANCE_METERS from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/robot_enters_region.py b/src/software/simulated_tests/pytest_validations/robot_enters_region.py similarity index 95% rename from src/software/simulated_tests/robot_enters_region.py rename to src/software/simulated_tests/pytest_validations/robot_enters_region.py index 2f7ac6d1c2..3a4ffbe8e9 100644 --- a/src/software/simulated_tests/robot_enters_region.py +++ b/src/software/simulated_tests/pytest_validations/robot_enters_region.py @@ -1,7 +1,7 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, @@ -57,7 +57,7 @@ def __repr__(self): "Check for " + str(self.req_robot_cnt) + " robots in region " - + ",".join(repr(self.regions)) + + ",".join(repr(region) for region in self.regions) ) diff --git a/src/software/simulated_tests/robot_enters_region_and_stops.py b/src/software/simulated_tests/pytest_validations/robot_enters_region_and_stops.py similarity index 95% rename from src/software/simulated_tests/robot_enters_region_and_stops.py rename to src/software/simulated_tests/pytest_validations/robot_enters_region_and_stops.py index 78210c6f43..2a9982f5be 100644 --- a/src/software/simulated_tests/robot_enters_region_and_stops.py +++ b/src/software/simulated_tests/pytest_validations/robot_enters_region_and_stops.py @@ -2,11 +2,13 @@ from software.py_constants import * from proto.import_all_protos import * -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( create_validation_types, create_validation_geometry, ) -from software.simulated_tests.robot_enters_region import RobotEntersRegion +from software.simulated_tests.pytest_validations.robot_enters_region import ( + RobotEntersRegion, +) from typing import override diff --git a/src/software/simulated_tests/pytest_validations/robot_received_ball.py b/src/software/simulated_tests/pytest_validations/robot_received_ball.py new file mode 100644 index 0000000000..41c359d769 --- /dev/null +++ b/src/software/simulated_tests/pytest_validations/robot_received_ball.py @@ -0,0 +1,60 @@ +import software.python_bindings as tbots_cpp +from proto.import_all_protos import * + +from software.simulated_tests.pytest_validations.validation import ( + Validation, + create_validation_geometry, + create_validation_types, +) +from typing import override + + +class RobotReceivedBall(Validation): + """Checks if a specific robot has received the ball (ball is near dribbler)""" + + def __init__(self, robot_id, tolerance=0.02): + """Constructs the validation object + + :param robot_id: The ID of the robot to check + :param tolerance: The tolerance for when we check if the robot has the ball + """ + self.robot_id = robot_id + self.tolerance = tolerance + + @override + def get_validation_status(self, world) -> ValidationStatus: + """Checks if the specific robot has received the ball + + :param world: The world msg to validate + :return: FAILING when the robot does not have the ball + PASSING when the robot has the ball + """ + ball_position = tbots_cpp.createPoint(world.ball.current_state.global_position) + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + if tbots_cpp.Robot(robot).isNearDribbler(ball_position, self.tolerance): + return ValidationStatus.PASSING + return ValidationStatus.FAILING + + @override + def get_validation_geometry(self, world) -> ValidationGeometry: + """Highlights the dribbler area of the robot""" + # TODO (#3637): create better validation geometry + for robot in world.friendly_team.team_robots: + if robot.id == self.robot_id: + return create_validation_geometry( + [tbots_cpp.Robot(robot).dribblerArea()] + ) + return create_validation_geometry() + + @override + def __repr__(self): + return f"Check that robot {self.robot_id} has received the ball" + + +( + RobotEventuallyReceivedBall, + RobotEventuallyDidNotReceiveBall, + RobotAlwaysHasBall, + RobotNeverHasBall, +) = create_validation_types(RobotReceivedBall) diff --git a/src/software/simulated_tests/robot_speed_threshold.py b/src/software/simulated_tests/pytest_validations/robot_speed_threshold.py similarity index 94% rename from src/software/simulated_tests/robot_speed_threshold.py rename to src/software/simulated_tests/pytest_validations/robot_speed_threshold.py index 52a9687ba7..5cf5474221 100644 --- a/src/software/simulated_tests/robot_speed_threshold.py +++ b/src/software/simulated_tests/pytest_validations/robot_speed_threshold.py @@ -1,11 +1,11 @@ import software.python_bindings as tbots_cpp from proto.import_all_protos import * from software.py_constants import * -from software.simulated_tests.speed_threshold_helpers import * +from software.simulated_tests.pytest_validations.speed_threshold_helpers import * from typing import override -from software.simulated_tests.validation import ( +from software.simulated_tests.pytest_validations.validation import ( Validation, create_validation_geometry, create_validation_types, diff --git a/src/software/simulated_tests/speed_threshold_helpers.py b/src/software/simulated_tests/pytest_validations/speed_threshold_helpers.py similarity index 100% rename from src/software/simulated_tests/speed_threshold_helpers.py rename to src/software/simulated_tests/pytest_validations/speed_threshold_helpers.py diff --git a/src/software/simulated_tests/validation.py b/src/software/simulated_tests/pytest_validations/validation.py similarity index 100% rename from src/software/simulated_tests/validation.py rename to src/software/simulated_tests/pytest_validations/validation.py index 3b5e70d538..1191bd1d99 100644 --- a/src/software/simulated_tests/validation.py +++ b/src/software/simulated_tests/pytest_validations/validation.py @@ -137,6 +137,44 @@ def flip_validation(self, world): return eventually_true, eventually_false, always_true, always_false +def create_validation_geometry(geometry=[]) -> ValidationGeometry: + """Creates a ValidationGeometry which is a visual representation of the + validation to be rendered as either green (PASSING) or red (FAILING) + + Given a list of (vectors, polygons, circles), creates a ValidationGeometry + proto containing the protobuf representations. + + :param geometry: A list of geom + :return: ValidationGeometry + """ + validation_geometry = ValidationGeometry() + + CREATE_PROTO_DISPATCH = { + tbots_cpp.Vector.__name__: tbots_cpp.createVectorProto, + tbots_cpp.Polygon.__name__: tbots_cpp.createPolygonProto, + tbots_cpp.Rectangle.__name__: tbots_cpp.createPolygonProto, + tbots_cpp.Circle.__name__: tbots_cpp.createCircleProto, + tbots_cpp.Segment.__name__: tbots_cpp.createSegmentProto, + tbots_cpp.Stadium.__name__: tbots_cpp.createStadiumProto, + } + + ADD_TO_VALIDATION_GEOMETRY_DISPATCH = { + tbots_cpp.Vector.__name__: validation_geometry.vectors.append, + tbots_cpp.Polygon.__name__: validation_geometry.polygons.append, + tbots_cpp.Rectangle.__name__: validation_geometry.polygons.append, + tbots_cpp.Circle.__name__: validation_geometry.circles.append, + tbots_cpp.Segment.__name__: validation_geometry.segments.append, + tbots_cpp.Stadium.__name__: validation_geometry.stadiums.append, + } + + for geom in geometry: + ADD_TO_VALIDATION_GEOMETRY_DISPATCH[type(geom).__name__]( + CREATE_PROTO_DISPATCH[type(geom).__name__](geom) + ) + + return validation_geometry + + def run_validation_sequence_sets( world, eventually_validation_sequence_set, always_validation_sequence_set ): @@ -219,41 +257,3 @@ def check_validation(validation_proto_set): for validation_proto in validation_proto_set.validations: if validation_proto.status == ValidationStatus.FAILING: raise AssertionError(validation_proto.failure_msg) - - -def create_validation_geometry(geometry=[]) -> ValidationGeometry: - """Creates a ValidationGeometry which is a visual representation of the - validation to be rendered as either green (PASSING) or red (FAILING) - - Given a list of (vectors, polygons, circles), creates a ValidationGeometry - proto containing the protobuf representations. - - :param geometry: A list of geom - :return: ValidationGeometry - """ - validation_geometry = ValidationGeometry() - - CREATE_PROTO_DISPATCH = { - tbots_cpp.Vector.__name__: tbots_cpp.createVectorProto, - tbots_cpp.Polygon.__name__: tbots_cpp.createPolygonProto, - tbots_cpp.Rectangle.__name__: tbots_cpp.createPolygonProto, - tbots_cpp.Circle.__name__: tbots_cpp.createCircleProto, - tbots_cpp.Segment.__name__: tbots_cpp.createSegmentProto, - tbots_cpp.Stadium.__name__: tbots_cpp.createStadiumProto, - } - - ADD_TO_VALIDATION_GEOMETRY_DISPATCH = { - tbots_cpp.Vector.__name__: validation_geometry.vectors.append, - tbots_cpp.Polygon.__name__: validation_geometry.polygons.append, - tbots_cpp.Rectangle.__name__: validation_geometry.polygons.append, - tbots_cpp.Circle.__name__: validation_geometry.circles.append, - tbots_cpp.Segment.__name__: validation_geometry.segments.append, - tbots_cpp.Stadium.__name__: validation_geometry.stadiums.append, - } - - for geom in geometry: - ADD_TO_VALIDATION_GEOMETRY_DISPATCH[type(geom).__name__]( - CREATE_PROTO_DISPATCH[type(geom).__name__](geom) - ) - - return validation_geometry diff --git a/src/software/simulated_tests/simulated_test_ball_model.py b/src/software/simulated_tests/simulated_test_ball_model.py index d1a845b2b7..3f8276a144 100644 --- a/src/software/simulated_tests/simulated_test_ball_model.py +++ b/src/software/simulated_tests/simulated_test_ball_model.py @@ -1,14 +1,14 @@ import pytest import software.python_bindings as tbots_cpp -from software.simulated_tests.robot_enters_region import * -from software.simulated_tests.ball_enters_region import * -from software.simulated_tests.ball_moves_in_direction import * -from software.simulated_tests.friendly_has_ball_possession import * -from software.simulated_tests.ball_speed_threshold import * -from software.simulated_tests.robot_speed_threshold import * -from software.simulated_tests.ball_stops_in_region import * -from software.simulated_tests.excessive_dribbling import * +from software.simulated_tests.pytest_validations.robot_enters_region import * +from software.simulated_tests.pytest_validations.ball_enters_region import * +from software.simulated_tests.pytest_validations.ball_moves_in_direction import * +from software.simulated_tests.pytest_validations.friendly_has_ball_possession import * +from software.simulated_tests.pytest_validations.ball_speed_threshold import * +from software.simulated_tests.pytest_validations.robot_speed_threshold import * +from software.simulated_tests.pytest_validations.ball_stops_in_region import * +from software.simulated_tests.pytest_validations.excessive_dribbling import * from proto.message_translation.tbots_protobuf import create_world_state from software.simulated_tests.simulated_test_fixture import ( pytest_main, diff --git a/src/software/simulated_tests/simulated_test_fixture.py b/src/software/simulated_tests/simulated_test_fixture.py index dc2eeef32f..e44ba226a1 100644 --- a/src/software/simulated_tests/simulated_test_fixture.py +++ b/src/software/simulated_tests/simulated_test_fixture.py @@ -8,7 +8,7 @@ import pytest from proto.import_all_protos import * -from software.simulated_tests import validation +from software.simulated_tests.pytest_validations import validation from software.simulated_tests.tbots_test_runner import TbotsTestRunner from software.thunderscope.thunderscope import Thunderscope from software.thunderscope.proto_unix_io import ProtoUnixIO