diff --git a/OpenSim/Common/Test/testComponentInterface.cpp b/OpenSim/Common/Test/testComponentInterface.cpp index 33919c0718..6284ad9e7b 100644 --- a/OpenSim/Common/Test/testComponentInterface.cpp +++ b/OpenSim/Common/Test/testComponentInterface.cpp @@ -32,6 +32,10 @@ #include #include #include + +#define CATCH_CONFIG_MAIN +#include + #include namespace @@ -444,7 +448,8 @@ class CompoundFoo : public Foo { SimTK_NICETYPENAME_LITERAL(Foo); SimTK_NICETYPENAME_LITERAL(Bar); -void testMisc() { +TEST_CASE("Component Interface Misc.") +{ // Define the Simbody system MultibodySystem system; @@ -836,7 +841,9 @@ void testMisc() { theWorld.print("Nested_" + modelFile); } -void testThrowOnDuplicateNames() { +// un-disable test for duplicate names when we re-enable the exception +TEST_CASE("Component Interface Throws on Duplicate Names", "[.disabled]") +{ TheWorld theWorld; theWorld.setName("World"); theWorld.finalizeFromProperties(); @@ -862,7 +869,8 @@ void testThrowOnDuplicateNames() { // finalizeFromProperties() after copying. This test makes sure that you get an // exception if you did not call finalizeFromProperties() before calling a // method like getComponentList(). -void testExceptionsFinalizeFromPropertiesAfterCopy() { +TEST_CASE("Component Interface Exceptions Finalize From Properties After Copy") +{ TheWorld theWorld; { MultibodySystem system; @@ -875,7 +883,8 @@ void testExceptionsFinalizeFromPropertiesAfterCopy() { } } -void testListInputs() { +TEST_CASE("Component Interface List Inputs") +{ MultibodySystem system; TheWorld theWorld; theWorld.setName("World"); @@ -937,7 +946,8 @@ void testListInputs() { ASSERT(tabReporter->getTable().getNumRows() == 0); } -void testListSockets() { +TEST_CASE("Component Interface List Sockets") +{ MultibodySystem system; TheWorld theWorld; theWorld.setName("world"); @@ -971,7 +981,8 @@ void testListSockets() { // TODO redo with the property list / the reference connect(). } -void testSocketCanConnectTo() { +TEST_CASE("Component Interface Socket::canConnectTo") +{ TheWorld theWorld; theWorld.setName("world"); @@ -993,7 +1004,8 @@ void testSocketCanConnectTo() { SimTK_TEST(!bar.getSocket("childFoo").canConnectTo(theWorld)); } -void testInputCanConnectTo() { +TEST_CASE("Component Interface Input::canConnectTo") +{ TheWorld theWorld; theWorld.setName("world"); @@ -1015,7 +1027,7 @@ void testInputCanConnectTo() { SimTK_TEST(!foo.getInput("input1").canConnectTo(bar)); } -void testComponentPathNames() +TEST_CASE("Component Interface Component Path Names") { Foo foo; foo.setName("LegWithConstrainedFoot/foot"); @@ -1145,7 +1157,8 @@ void testComponentPathNames() top.connect(); } -void testFindComponent() { +TEST_CASE("Component Interface Component::findComponent") +{ class A : public Component { OpenSim_DECLARE_CONCRETE_OBJECT(A, Component); public: @@ -1200,7 +1213,8 @@ void testFindComponent() { SimTK_TEST(&b3->getConnectee("socket_a") == a3); } -void testTraversePathToComponent() { +TEST_CASE("Component Interface can Traverse Path to Component") +{ class A : public Component { OpenSim_DECLARE_CONCRETE_OBJECT(A, Component); public: @@ -1294,8 +1308,8 @@ void testTraversePathToComponent() { SimTK_TEST(&top.getComponent("tx/tx") == btx); } -void testGetStateVariableValue() { - +TEST_CASE("Component Interface Component::getStateVariableValue") +{ TheWorld top; top.setName("top"); Sub* a = new Sub(); @@ -1329,7 +1343,8 @@ void testGetStateVariableValue() { OpenSim::Exception); } -void testGetStateVariableValueComponentPath() { +TEST_CASE("Component Interface getStateVariableValue with Component Path") +{ using CP = ComponentPath; TheWorld top; @@ -1365,7 +1380,7 @@ void testGetStateVariableValueComponentPath() { OpenSim::Exception); } -void testInputOutputConnections() +TEST_CASE("Component Interface Input/Output Connections") { { TheWorld world; @@ -1468,7 +1483,8 @@ void testInputOutputConnections() } } -void testInputConnecteePaths() { +TEST_CASE("Component Interface Input Connectee Paths") +{ { std::string componentPath, outputName, channelName, alias; AbstractInput::parseConnecteePath("/foo/bar|output", @@ -1513,7 +1529,8 @@ void testInputConnecteePaths() { // TODO test invalid names as well. } -void testExceptionsForConnecteeTypeMismatch() { +TEST_CASE("Component Interface Exceptions when Connectee Type Mismatches") +{ // Create Component classes for use in the following tests. // -------------------------------------------------------- // This class has Outputs. @@ -1637,7 +1654,8 @@ void testExceptionsForConnecteeTypeMismatch() { } } -void testExceptionsSocketNameExistsAlready() { +TEST_CASE("Component Interface Throws Exceptions if Socket Name Exists Already") +{ // Make sure that it is not possible for a class to have more than one // socket with a given name, even if the connectee types are different. @@ -1681,7 +1699,8 @@ void testExceptionsSocketNameExistsAlready() { // leads to a compiling error (duplicate member variable). } -void testExceptionsInputNameExistsAlready() { +TEST_CASE("Component Interface Throws Exception if Input Name Exists Already") +{ // Make sure that it is not possible for a class to have more than one // input with a given name, even if the connectee types are different. @@ -1744,7 +1763,8 @@ void testExceptionsInputNameExistsAlready() { } } -void testExceptionsOutputNameExistsAlready() { +TEST_CASE("Component Interface Throws Exceptions if Output Name Exists Already") +{ // Make sure that it is not possible for a class to have more than one // output with a given name, even if the types are different. @@ -1827,7 +1847,8 @@ void assertEqual(const RowVec& a, const RowVec& b) { ASSERT_EQUAL(a[i], b[i], 1e-10); } -void testTableSource() { +TEST_CASE("Component Interface Table Source") +{ using namespace OpenSim; using namespace SimTK; @@ -1925,7 +1946,8 @@ void testTableSource() { std::cout << report << std::endl; } -void testTableReporter() { +TEST_CASE("Component Interface TableReporter Usage") +{ // TableReporter works fine even if its input has no connectees. { TheWorld model; @@ -1987,11 +2009,14 @@ void writeTimeSeriesTableForInputConnecteeSerialization() { dataFileNameForInputConnecteeSerialization); } -void testListInputConnecteeSerialization() { +TEST_CASE("Component Interface List Input Connectee Serialization Behavior") +{ // We build a model, store the input connectee paths, then // recreate the same model from a serialization, and make sure the // connectee paths are the same. + writeTimeSeriesTableForInputConnecteeSerialization(); + // Helper function. auto getConnecteePaths = [](const AbstractInput& in) { const auto numConnectees = in.getNumConnectees(); @@ -2085,10 +2110,12 @@ void testListInputConnecteeSerialization() { } } -void testSingleValueInputConnecteeSerialization() { - +TEST_CASE("Component Interface Single Value Input Connectee Serialization Behavior") +{ // Test normal behavior of single-value input (de)serialization. // ------------------------------------------------------------- + + writeTimeSeriesTableForInputConnecteeSerialization(); // Build a model and serialize it. std::string modelFileName = "testComponentInterface_" @@ -2254,7 +2281,8 @@ void testSingleValueInputConnecteeSerialization() { } } -void testAliasesAndLabels() { +TEST_CASE("Component Interface Aliases and Labels Behavior") +{ auto theWorld = std::unique_ptr(new TheWorld()); theWorld->setName("world"); @@ -2327,8 +2355,8 @@ void testAliasesAndLabels() { SimTK_TEST(foo->getInput("listInput1").getLabel(1) == "thud"); } -void testGetAbsolutePathStringSpeed() { - +TEST_CASE("Component Interface Get Absolute Path String Speed") +{ std::clock_t constructStartTime = std::clock(); TheWorld* A = new TheWorld(); @@ -2385,7 +2413,8 @@ void testGetAbsolutePathStringSpeed() { cout << "getName avgTime = " << avgTime / numTrials << "s" << endl; } -void testFormattedDateTime() { +TEST_CASE("Component Interface Formatted DateTime Works as Expected") +{ std::string withMicroseconds = getFormattedDateTime(true, "%Y"); std::string withoutMicroseconds = getFormattedDateTime(false, "%Y"); SimTK_TEST(withMicroseconds.find(withoutMicroseconds) == 0); @@ -2403,7 +2432,8 @@ struct ComponentWithCacheVariable : public Component { template using CacheVariable = Component::CacheVariable; -void testCacheVariableInterface() { +TEST_CASE("Component Interface CacheVariable Behavior") +{ // can default-initialize without throwing an exception { CacheVariable cv; @@ -2631,7 +2661,7 @@ void testCacheVariableInterface() { // if downstream code tries to read an optional SimpleProperty without // checking whether it's populated or not, it should throw an exception // rather than segfaulting -void testIncorrectlyReadingAnOptionalSimplePropertyDoesNotSegfault() +TEST_CASE("Component Interface: Incorrectly Reading An Optional Simple Property Should Not Segfault (#3409/#3411)") { ComponentWithOptionalSimpleProperty c; @@ -2650,7 +2680,7 @@ void testIncorrectlyReadingAnOptionalSimplePropertyDoesNotSegfault() // OpenSim <=4.4) tries to read an optional ObjectProperty without checking // whether it's populated or not, it should throw an exception rather // than segfaulting -void testIncorrectlyReadingAnOptionalObjectPropertyDoesNotSegfault() +TEST_CASE("Component Interface: Incorrectly Reading an Optional Object Property Should Not Segfault (#3347)") { ComponentWithOptionalObjectProperty c; @@ -2663,51 +2693,11 @@ void testIncorrectlyReadingAnOptionalObjectPropertyDoesNotSegfault() } } -int main() { - - //Register new types for testing deserialization +const bool g_TestFixtureTypesAreRegistered = []() +{ + // ensure new types are globally registered for testing deserialization Object::registerType(Foo()); Object::registerType(Bar()); Object::registerType(TheWorld()); - - SimTK_START_TEST("testComponentInterface"); - SimTK_SUBTEST(testMisc); - // Uncomment test for duplicate names when we re-enable the exception - //SimTK_SUBTEST(testThrowOnDuplicateNames); - SimTK_SUBTEST(testExceptionsFinalizeFromPropertiesAfterCopy); - SimTK_SUBTEST(testListInputs); - SimTK_SUBTEST(testListSockets); - SimTK_SUBTEST(testSocketCanConnectTo); - SimTK_SUBTEST(testInputCanConnectTo); - SimTK_SUBTEST(testComponentPathNames); - SimTK_SUBTEST(testFindComponent); - SimTK_SUBTEST(testTraversePathToComponent); - SimTK_SUBTEST(testGetStateVariableValue); - SimTK_SUBTEST(testGetStateVariableValueComponentPath); - SimTK_SUBTEST(testInputOutputConnections); - SimTK_SUBTEST(testInputConnecteePaths); - SimTK_SUBTEST(testExceptionsForConnecteeTypeMismatch); - SimTK_SUBTEST(testExceptionsSocketNameExistsAlready); - SimTK_SUBTEST(testExceptionsInputNameExistsAlready); - SimTK_SUBTEST(testExceptionsOutputNameExistsAlready); - SimTK_SUBTEST(testTableSource); - SimTK_SUBTEST(testTableReporter); - SimTK_SUBTEST(testAliasesAndLabels); - - writeTimeSeriesTableForInputConnecteeSerialization(); - SimTK_SUBTEST(testListInputConnecteeSerialization); - SimTK_SUBTEST(testSingleValueInputConnecteeSerialization); - - // This is commented out since it adds ~20-30sec without testing - // any new functionality. Make sure to uncomment to use (and - // consider commenting other subtests for more stable benchmark). - //SimTK_SUBTEST(testGetAbsolutePathStringSpeed); - - SimTK_SUBTEST(testFormattedDateTime); - SimTK_SUBTEST(testCacheVariableInterface); - SimTK_SUBTEST(testIncorrectlyReadingAnOptionalSimplePropertyDoesNotSegfault); - SimTK_SUBTEST(testIncorrectlyReadingAnOptionalObjectPropertyDoesNotSegfault); - - - SimTK_END_TEST(); -} + return true; +}();