Skip to content

Commit 9f5fc99

Browse files
yuvaltassacopybara-github
authored andcommitted
Convert monolithic RecompileCompare and WriteReadCompare tests into test suites, one test per file.
PiperOrigin-RevId: 890149850 Change-Id: Ib3e8c032a7b43b4a3f85e7a922e25987050cd77c
1 parent 0021564 commit 9f5fc99

3 files changed

Lines changed: 254 additions & 196 deletions

File tree

test/CMakeLists.txt

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,36 @@ macro(mujoco_test name)
5454
endif()
5555
target_include_directories(${name} PRIVATE ${MUJOCO_TEST_INCLUDE})
5656
set_target_properties(${name} PROPERTIES BUILD_RPATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
57-
# gtest_discover_tests is recommended over gtest_add_tests, but has some issues in Windows.
58-
gtest_add_tests(
59-
TARGET ${name}
60-
SOURCES ${name}.cc
61-
WORKING_DIRECTORY ${MUJOCO_TEST_WORKING_DIR}
62-
TEST_LIST testList
63-
)
64-
if(WIN32)
65-
set_tests_properties(
66-
${testList} PROPERTIES ENVIRONMENT "PATH=$<TARGET_FILE_DIR:mujoco>;$ENV{PATH}"
57+
# gtest_discover_tests is recommended over gtest_add_tests, but has issues on Windows.
58+
# It also requires a GoogleTest binary, so we fall back for custom MAIN_TARGET (e.g. benchmarks).
59+
if(WIN32 OR _ARGS_MAIN_TARGET)
60+
gtest_add_tests(
61+
TARGET ${name}
62+
SOURCES ${name}.cc
63+
WORKING_DIRECTORY ${MUJOCO_TEST_WORKING_DIR}
64+
TEST_LIST testList
6765
)
68-
endif()
69-
if(_ARGS_PROPERTIES)
70-
set_tests_properties(${testList} PROPERTIES ${_ARGS_PROPERTIES})
66+
if(WIN32)
67+
set_tests_properties(
68+
${testList} PROPERTIES ENVIRONMENT "PATH=$<TARGET_FILE_DIR:mujoco>;$ENV{PATH}"
69+
)
70+
endif()
71+
if(_ARGS_PROPERTIES)
72+
set_tests_properties(${testList} PROPERTIES ${_ARGS_PROPERTIES})
73+
endif()
74+
else()
75+
if(_ARGS_PROPERTIES)
76+
gtest_discover_tests(
77+
${name}
78+
WORKING_DIRECTORY ${MUJOCO_TEST_WORKING_DIR}
79+
PROPERTIES ${_ARGS_PROPERTIES}
80+
)
81+
else()
82+
gtest_discover_tests(
83+
${name}
84+
WORKING_DIRECTORY ${MUJOCO_TEST_WORKING_DIR}
85+
)
86+
endif()
7187
endif()
7288

7389
endmacro()
@@ -102,3 +118,4 @@ add_subdirectory(xml)
102118
add_subdirectory(plugin/elasticity)
103119
add_subdirectory(plugin/actuator)
104120
add_subdirectory(experimental)
121+

test/user/user_api_test.cc

Lines changed: 92 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414

1515
// Tests for user/user_api.cc.
1616

17+
#include <algorithm>
1718
#include <array>
19+
#include <cctype>
1820
#include <cstddef>
1921
#include <cstdint>
20-
#include <filesystem>
22+
#include <filesystem> // NOLINT
2123
#include <functional>
2224
#include <map>
2325
#include <memory>
@@ -515,97 +517,116 @@ TEST_F(MujocoTest, ModifyShellInertiaFails) {
515517
}
516518

517519
// ------------------- test recompilation multiple files -----------------------
518-
TEST_F(MujocoTest, RecompileCompare) {
519-
mjtNum tol = 0;
520-
std::string field = "";
521-
522-
// full precision float printing
523-
FullFloatPrecision increase_precision;
524520

525-
// loop over all xml files in data
526-
std::vector<std::string> paths = {GetTestDataFilePath("."),
527-
GetModelPath(".")};
521+
std::vector<std::string> GetRecompileTestModels() {
522+
std::vector<std::string> models;
528523
std::string ext(".xml");
529-
for (auto const& path : paths) {
530-
for (auto &p : std::filesystem::recursive_directory_iterator(path)) {
524+
for (const auto& path : {GetTestDataFilePath("."), GetModelPath(".")}) {
525+
for (const auto& p : std::filesystem::recursive_directory_iterator(path)) {
531526
if (p.path().extension() == ext) {
532527
std::string xml = p.path().string();
533-
534-
// if file is meant to fail or model is too slow to load, skip it
535-
if (absl::StrContains(p.path().string(), "malformed_") ||
536-
absl::StrContains(p.path().string(), "_fail") ||
537-
absl::StrContains(p.path().string(), "touch_grid") ||
538-
absl::StrContains(p.path().string(), "perf") ||
539-
absl::StrContains(p.path().string(), "cow")) {
528+
if (absl::StrContains(xml, "malformed_") ||
529+
absl::StrContains(xml, "_fail") ||
530+
absl::StrContains(xml, "touch_grid") ||
531+
absl::StrContains(xml, "perf") ||
532+
absl::StrContains(xml, "cow")) {
540533
continue;
541534
}
535+
models.push_back(xml);
536+
}
537+
}
538+
}
539+
return models;
540+
}
542541

543-
// load spec
544-
std::array<char, 1000> err;
545-
mjSpec* s = mj_parseXML(xml.c_str(), 0, err.data(), err.size());
546-
547-
ASSERT_THAT(s, NotNull())
548-
<< "Failed to load " << xml << ": " << err.data();
549-
550-
// copy spec
551-
mjSpec* s_copy = mj_copySpec(s);
542+
class RecompileCompareTest : public MujocoTest,
543+
public ::testing::WithParamInterface<std::string> {
544+
public:
545+
};
546+
TEST_P(RecompileCompareTest, RecompileCompare) {
547+
std::string xml = GetParam();
548+
std::string field = "";
552549

553-
// compare signature
554-
EXPECT_EQ(s->element->signature, s_copy->element->signature) << xml;
550+
FullFloatPrecision increase_precision;
555551

556-
// compile twice and compare
557-
mjModel* m_old = mj_compile(s, nullptr);
552+
// load spec
553+
std::array<char, 1000> err;
554+
mjSpec* s = mj_parseXML(xml.c_str(), 0, err.data(), err.size());
558555

559-
ASSERT_THAT(m_old, NotNull())
560-
<< "Failed to compile " << xml << ": " << mjs_getError(s);
556+
if (!s) {
557+
GTEST_SKIP() << "Failed to load " << xml << ": " << err.data();
558+
}
561559

562-
mjModel* m_new = mj_compile(s, nullptr);
563-
mjModel* m_copy = mj_compile(s_copy, nullptr);
560+
// copy spec
561+
mjSpec* s_copy = mj_copySpec(s);
564562

565-
// compare signature
566-
EXPECT_EQ(m_old->signature, m_new->signature) << xml;
567-
EXPECT_EQ(m_old->signature, m_copy->signature) << xml;
563+
// compare signature
564+
EXPECT_EQ(s->element->signature, s_copy->element->signature) << xml;
568565

569-
ASSERT_THAT(m_new, NotNull())
570-
<< "Failed to recompile " << xml << ": " << mjs_getError(s);
571-
ASSERT_THAT(m_copy, NotNull())
572-
<< "Failed to compile " << xml << ": " << mjs_getError(s_copy);
566+
// compile twice and compare
567+
mjModel* m_old = mj_compile(s, nullptr);
573568

574-
EXPECT_LE(CompareModel(m_old, m_new, field), tol)
575-
<< "Compiled and recompiled models are different!\n"
576-
<< "Affected file " << p.path().string() << '\n'
577-
<< "Different field: " << field << '\n';
569+
if (!m_old) {
570+
mj_deleteSpec(s);
571+
GTEST_SKIP() << "Failed to compile " << xml << ": " << mjs_getError(s);
572+
}
578573

579-
EXPECT_LE(CompareModel(m_old, m_copy, field), tol)
580-
<< "Original and copied models are different!\n"
581-
<< "Affected file " << p.path().string() << '\n'
582-
<< "Different field: " << field << '\n';
574+
mjModel* m_new = mj_compile(s, nullptr);
575+
mjModel* m_copy = mj_compile(s_copy, nullptr);
583576

584-
// copy to a new spec, compile and compare
585-
mjSpec* s_copy2 = mj_copySpec(s);
586-
mjModel* m_copy2 = mj_compile(s_copy2, nullptr);
577+
// compare signature
578+
EXPECT_EQ(m_old->signature, m_new->signature) << xml;
579+
EXPECT_EQ(m_old->signature, m_copy->signature) << xml;
587580

588-
ASSERT_THAT(m_copy2, NotNull())
589-
<< "Failed to compile " << xml << ": " << mjs_getError(s_copy2);
581+
ASSERT_THAT(m_new, NotNull())
582+
<< "Failed to recompile " << xml << ": " << mjs_getError(s);
583+
ASSERT_THAT(m_copy, NotNull())
584+
<< "Failed to compile " << xml << ": " << mjs_getError(s_copy);
590585

591-
EXPECT_LE(CompareModel(m_old, m_copy2, field), tol)
592-
<< "Original and re-copied models are different!\n"
593-
<< "Affected file " << p.path().string() << '\n'
594-
<< "Different field: " << field << '\n';
586+
mjtNum tol = 0;
595587

596-
// delete models
597-
mj_deleteSpec(s);
598-
mj_deleteSpec(s_copy);
599-
mj_deleteSpec(s_copy2);
600-
mj_deleteModel(m_old);
601-
mj_deleteModel(m_new);
602-
mj_deleteModel(m_copy);
603-
mj_deleteModel(m_copy2);
604-
}
605-
}
606-
}
588+
EXPECT_LE(CompareModel(m_old, m_new, field), tol)
589+
<< "Compiled and recompiled models are different!\n"
590+
<< "Affected file " << xml << '\n'
591+
<< "Different field: " << field << '\n';
592+
593+
EXPECT_LE(CompareModel(m_old, m_copy, field), tol)
594+
<< "Original and copied models are different!\n"
595+
<< "Affected file " << xml << '\n'
596+
<< "Different field: " << field << '\n';
597+
598+
// copy to a new spec, compile and compare
599+
mjSpec* s_copy2 = mj_copySpec(s);
600+
mjModel* m_copy2 = mj_compile(s_copy2, nullptr);
601+
602+
ASSERT_THAT(m_copy2, NotNull())
603+
<< "Failed to compile " << xml << ": " << mjs_getError(s_copy2);
604+
605+
EXPECT_LE(CompareModel(m_old, m_copy2, field), tol)
606+
<< "Original and re-copied models are different!\n"
607+
<< "Affected file " << xml << '\n'
608+
<< "Different field: " << field << '\n';
609+
610+
mj_deleteModel(m_new);
611+
mj_deleteModel(m_copy);
612+
mj_deleteModel(m_copy2);
613+
mj_deleteSpec(s_copy);
614+
mj_deleteSpec(s_copy2);
615+
mj_deleteSpec(s);
616+
mj_deleteModel(m_old);
607617
}
608618

619+
INSTANTIATE_TEST_SUITE_P(
620+
AllModels, RecompileCompareTest,
621+
::testing::ValuesIn(GetRecompileTestModels()),
622+
[](const ::testing::TestParamInfo<std::string>& info) {
623+
std::string name = std::filesystem::path(info.param).filename().string();
624+
std::replace_if(
625+
name.begin(), name.end(),
626+
[](char c) { return !std::isalnum(c); }, '_');
627+
return name + "_" + std::to_string(info.index);
628+
});
629+
609630
TEST_F(MujocoTest, RecompileEdit) {
610631
static constexpr char xml[] = R"(
611632
<mujoco>

0 commit comments

Comments
 (0)