diff --git a/src/shared/test_util/tbots_gtest_main.cpp b/src/shared/test_util/tbots_gtest_main.cpp index 82b96ba1e1..895f928651 100644 --- a/src/shared/test_util/tbots_gtest_main.cpp +++ b/src/shared/test_util/tbots_gtest_main.cpp @@ -5,10 +5,37 @@ std::string runtime_dir = "/tmp/tbots/yellow_test"; +/** + * Portable wrapper for feenableexcept. Use to specify which floating-point + * exceptions should crash the program when they occur. + * + * @note On MacOS ARM, there are no floating-point exception traps, so tests may + * pass on MacOS that wouldn't pass on other platforms if floating-point + * exceptions occur. + * + * @param excepts A bitmask of floating-point exceptions to be enabled. + * @return True on success, false on failure to set floating-point exceptions. + */ +bool enable_fp_exceptions(unsigned int excepts) +{ +#if defined(__linux__) && defined(__GNUC__) + feenableexcept(excepts); + return true; +#else + // Unsupported platform + return false; +#endif +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); - feenableexcept(FE_INVALID | FE_OVERFLOW); + + // Crash on invalid operations like sqrt of negative and floating-point overflow + if (!enable_fp_exceptions(FE_INVALID | FE_OVERFLOW)) + { + std::cerr << "Warning: Could not enable floating-point exceptions." << std::endl; + } LoggerSingleton::initializeLogger(runtime_dir, nullptr); diff --git a/src/software/math/math_functions_test.cpp b/src/software/math/math_functions_test.cpp index c5a48dd605..033aee4d29 100644 --- a/src/software/math/math_functions_test.cpp +++ b/src/software/math/math_functions_test.cpp @@ -2,69 +2,71 @@ #include +#include + TEST(LinearUtilFunctionTest, testZeroCase) { double out = linear(0, 0, 2); - EXPECT_EQ(out, 0.5); + EXPECT_NEAR(out, 0.5, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testOneQuarter) { double out = linear(-1, 0, 4); - EXPECT_EQ(out, 0.25); + EXPECT_NEAR(out, 0.25, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testTwoThirds) { double out = linear(0.75, 0, 4.5); - EXPECT_EQ(out, 2.0 / 3.0); + EXPECT_NEAR(out, 2.0 / 3.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMinimumNoOffset) { double out = linear(-1.5, 0, 3); - EXPECT_EQ(out, 0.0); + EXPECT_NEAR(out, 0.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMaximumNoOffset) { double out = linear(2.5, 0, 5.0); - EXPECT_EQ(out, 1.0); -} - -TEST(LinearUtilFunctionTest, testClampBelowNoOffset) -{ - double out = linear(-2, 0, 1); - EXPECT_EQ(out, 0.0); -} - -TEST(LinearUtilFunctionTest, testClampAboveNoOffset) -{ - double out = linear(4.2, 0, 6); - EXPECT_EQ(out, 1.0); + EXPECT_NEAR(out, 1.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMinimumNegativeOffset) { double out = linear(-4, -2, 4); - EXPECT_EQ(out, 0.0); + EXPECT_NEAR(out, 0.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMaximumNegativeOffset) { double out = linear(1.5, -1, 5.0); - EXPECT_EQ(out, 1.0); + EXPECT_NEAR(out, 1.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMinimumPositiveOffset) { double out = linear(0, 3, 6); - EXPECT_EQ(out, 0.0); + EXPECT_NEAR(out, 0.0, std::numeric_limits::epsilon()); } TEST(LinearUtilFunctionTest, testMaximumPositiveOffset) { double out = linear(6, 1.5, 9); + EXPECT_NEAR(out, 1.0, std::numeric_limits::epsilon()); +} + +TEST(LinearUtilFunctionTest, testClampBelowNoOffset) +{ + double out = linear(-2, 0, 1); + EXPECT_EQ(out, 0.0); +} + +TEST(LinearUtilFunctionTest, testClampAboveNoOffset) +{ + double out = linear(4.2, 0, 6); EXPECT_EQ(out, 1.0); } diff --git a/src/software/simulation/er_force_simulator_test.cpp b/src/software/simulation/er_force_simulator_test.cpp index 776376c1ce..0a5713f1f6 100644 --- a/src/software/simulation/er_force_simulator_test.cpp +++ b/src/software/simulation/er_force_simulator_test.cpp @@ -1,8 +1,6 @@ #include "software/simulation/er_force_simulator.h" #include -// TODO (#2419): remove this -#include #include "proto/message_translation/er_force_world.h" #include "proto/message_translation/tbots_protobuf.h" @@ -15,8 +13,6 @@ class ErForceSimulatorTest : public ::testing::Test protected: void SetUp() override { - // TODO (#2419): remove this to re-enable sigfpe checks - fedisableexcept(FE_INVALID | FE_OVERFLOW); auto realism_config = ErForceSimulator::createDefaultRealismConfig(); simulator = std::make_shared(TbotsProto::FieldType::DIV_B, robot_constants, realism_config); diff --git a/src/software/thunderscope/requirements_lock.darwin.txt b/src/software/thunderscope/requirements_lock.darwin.txt index 87532ad2ba..55045c79c5 100644 --- a/src/software/thunderscope/requirements_lock.darwin.txt +++ b/src/software/thunderscope/requirements_lock.darwin.txt @@ -120,7 +120,13 @@ pyqtgraph==0.13.7 \ --hash=sha256:64f84f1935c6996d0e09b1ee66fe478a7771e3ca6f3aaa05f00f6e068321d9e3 \ --hash=sha256:7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a # via -r software/thunderscope/requirements.in +qtawesome==1.4.0 \ + --hash=sha256:783e414d1317f3e978bf67ea8e8a1b1498bad9dbd305dec814027e3b50521be6 \ + --hash=sha256:a4d689fa071c595aa6184171ce1f0f847677cb8d2db45382c43129f1d72a3d93 + # via -r software/thunderscope/requirements.in qtpy==2.4.2 \ --hash=sha256:5a696b1dd7a354cb330657da1d17c20c2190c72d4888ba923f8461da67aa1a1c \ --hash=sha256:9d6ec91a587cc1495eaebd23130f7619afa5cdd34a277acb87735b4ad7c65156 - # via pyqt-toast-notification + # via + # pyqt-toast-notification + # qtawesome diff --git a/src/software/util/typename/typename_test.cpp b/src/software/util/typename/typename_test.cpp index f28a4b25cd..4acd815c25 100644 --- a/src/software/util/typename/typename_test.cpp +++ b/src/software/util/typename/typename_test.cpp @@ -17,7 +17,13 @@ class TestTypeA : public TestType TEST(TypeNameTest, abstract_base_class_concrete_subtype) { std::shared_ptr test_type = std::make_shared(); +#ifdef __APPLE__ + // With clang / libc++, the standard library uses an inline namespace '__1' for + // ABI versioning, which is reflected in the demangled type name. + EXPECT_EQ("std::__1::shared_ptr", objectTypeName(test_type)); +#else EXPECT_EQ("std::shared_ptr", objectTypeName(test_type)); +#endif EXPECT_EQ("TestTypeA", objectTypeName(*test_type)); } diff --git a/src/starlark/nanopb/nanopb.bzl b/src/starlark/nanopb/nanopb.bzl index 83fc6bf648..cdec9947de 100644 --- a/src/starlark/nanopb/nanopb.bzl +++ b/src/starlark/nanopb/nanopb.bzl @@ -227,6 +227,11 @@ def _construct_cc_info( user_compile_flags = copts, ) + # Flags required for macos linker which allow symbols to be resolved at runtime + link_flags = [] + if "darwin" in cc_toolchain.cpu: + link_flags = ["-Wl,-undefined,dynamic_lookup"] + (linking_context, linking_outputs) = \ cc_common.create_linking_context_from_compilation_outputs( name = "link_nanopb_outputs", @@ -235,6 +240,7 @@ def _construct_cc_info( feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, linking_contexts = nanopb_linking_contexts, + user_link_flags = link_flags, ) extra_context = cc_common.create_compilation_context(