|
14 | 14 |
|
15 | 15 | // Tests for user/user_api.cc. |
16 | 16 |
|
| 17 | +#include <algorithm> |
17 | 18 | #include <array> |
| 19 | +#include <cctype> |
18 | 20 | #include <cstddef> |
19 | 21 | #include <cstdint> |
20 | | -#include <filesystem> |
| 22 | +#include <filesystem> // NOLINT |
21 | 23 | #include <functional> |
22 | 24 | #include <map> |
23 | 25 | #include <memory> |
@@ -515,97 +517,116 @@ TEST_F(MujocoTest, ModifyShellInertiaFails) { |
515 | 517 | } |
516 | 518 |
|
517 | 519 | // ------------------- 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; |
524 | 520 |
|
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; |
528 | 523 | 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)) { |
531 | 526 | if (p.path().extension() == ext) { |
532 | 527 | 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")) { |
540 | 533 | continue; |
541 | 534 | } |
| 535 | + models.push_back(xml); |
| 536 | + } |
| 537 | + } |
| 538 | + } |
| 539 | + return models; |
| 540 | +} |
542 | 541 |
|
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 = ""; |
552 | 549 |
|
553 | | - // compare signature |
554 | | - EXPECT_EQ(s->element->signature, s_copy->element->signature) << xml; |
| 550 | + FullFloatPrecision increase_precision; |
555 | 551 |
|
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()); |
558 | 555 |
|
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 | + } |
561 | 559 |
|
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); |
564 | 562 |
|
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; |
568 | 565 |
|
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); |
573 | 568 |
|
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 | + } |
578 | 573 |
|
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); |
583 | 576 |
|
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; |
587 | 580 |
|
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); |
590 | 585 |
|
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; |
595 | 587 |
|
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); |
607 | 617 | } |
608 | 618 |
|
| 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 | + |
609 | 630 | TEST_F(MujocoTest, RecompileEdit) { |
610 | 631 | static constexpr char xml[] = R"( |
611 | 632 | <mujoco> |
|
0 commit comments