#include "UnitTests.hpp"
#include <any>
#include <stdexcept>
#include <type_traits>
#define DEFINE_GETBODYA \
[[maybe_unused]] BodyID GetBodyA(const JointTester&) noexcept \
{ \
return InvalidBodyID; \
}
#define DEFINE_GETBODYB \
[[maybe_unused]] BodyID GetBodyB(const JointTester&) noexcept \
{ \
return InvalidBodyID; \
}
#define DEFINE_GETCOLLIDECONNECTED \
[[maybe_unused]] bool GetCollideConnected(const JointTester&) noexcept \
{ \
return false; \
}
#define DEFINE_SHIFTORIGIN \
[[maybe_unused]] bool ShiftOrigin(JointTester&, Length2) noexcept \
{ \
return false; \
}
#define DEFINE_INITVELOCITY \
[[maybe_unused]] void InitVelocity(JointTester&, const Span<BodyConstraint>&, \
const StepConf&, const ConstraintSolverConf&) \
{ \
}
#define DEFINE_SOLVEVELOCITY \
[[maybe_unused]] bool SolveVelocity(JointTester&, const Span<BodyConstraint>&, \
const StepConf&) \
{ \
return true; \
}
#define DEFINE_SOLVEPOSITION \
[[maybe_unused]] bool SolvePosition(const JointTester&, const Span<BodyConstraint>&, \
const ConstraintSolverConf&) \
{ \
return true; \
}
#define DEFINE_EQUALS \
[[maybe_unused]] bool operator==(const JointTester& lhs, const JointTester& rhs) noexcept \
{ \
return lhs.number == rhs.number; \
}
namespace test {
namespace sans_none {
namespace {
struct JointTester {
static int defaultConstructorCalled;
static int copyConstructorCalled;
static int moveConstructorCalled;
static int copyAssignmentCalled;
static int moveAssignmentCalled;
static void resetClass()
{
defaultConstructorCalled = 0;
copyConstructorCalled = 0;
moveConstructorCalled = 0;
copyAssignmentCalled = 0;
moveAssignmentCalled = 0;
}
int number = 0;
std::string data;
JointTester()
{
++defaultConstructorCalled;
}
JointTester(const JointTester& other): number{other.number}, data{other.data}
{
++copyConstructorCalled;
}
JointTester(JointTester&& other): number{std::move(other.number)}, data{std::move(other.data)}
{
++moveConstructorCalled;
}
JointTester& operator=(const JointTester& other)
{
number = other.number;
data = other.data;
++copyAssignmentCalled;
return *this;
}
JointTester& operator=(JointTester&& other)
{
number = std::move(other.number);
data = std::move(other.data);
++moveAssignmentCalled;
return *this;
}
};
int JointTester::defaultConstructorCalled;
int JointTester::copyConstructorCalled;
int JointTester::moveConstructorCalled;
int JointTester::copyAssignmentCalled;
int JointTester::moveAssignmentCalled;
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_getbodya {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_getbodyb {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_getcollideconnected {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_shiftorigin {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_initvelocity {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_solvevelocity {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEPOSITION;
DEFINE_EQUALS;
}
}
namespace sans_solveposition {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_EQUALS;
}
}
namespace sans_equals {
namespace {
struct JointTester {
int number = 0;
};
DEFINE_GETBODYA;
DEFINE_GETBODYB;
DEFINE_GETCOLLIDECONNECTED;
DEFINE_SHIFTORIGIN;
DEFINE_INITVELOCITY;
DEFINE_SOLVEVELOCITY;
DEFINE_SOLVEPOSITION;
}
}
namespace sans_all {
namespace {
struct JointTester {
int number = 0;
};
}
}
static_assert(IsValidJointTypeV<sans_none::JointTester>);
static_assert(!IsValidJointTypeV<sans_getbodya::JointTester>);
static_assert(!IsValidJointTypeV<sans_getbodyb::JointTester>);
static_assert(!IsValidJointTypeV<sans_getcollideconnected::JointTester>);
static_assert(!IsValidJointTypeV<sans_shiftorigin::JointTester>);
static_assert(!IsValidJointTypeV<sans_initvelocity::JointTester>);
static_assert(!IsValidJointTypeV<sans_solvevelocity::JointTester>);
static_assert(!IsValidJointTypeV<sans_solveposition::JointTester>);
static_assert(!IsValidJointTypeV<sans_equals::JointTester>);
static_assert(!IsValidJointTypeV<sans_all::JointTester>);
}
TEST(JointConf, Traits)
{
EXPECT_TRUE(std::is_default_constructible_v<JointConf>);
EXPECT_TRUE(std::is_nothrow_default_constructible_v<JointConf>);
EXPECT_TRUE(std::is_copy_constructible_v<JointConf>);
EXPECT_TRUE(std::is_nothrow_copy_constructible_v<JointConf>);
}
TEST(JointBuilder, Construction)
{
EXPECT_EQ(JointBuilder<JointConf>{}.collideConnected, false);
}
TEST(JointBuilder, UseBodyA)
{
const auto b =
static_cast<BodyID>(2);
EXPECT_NE(JointBuilder<JointConf>{}.bodyA, b);
EXPECT_EQ(JointBuilder<JointConf>{}.UseBodyA(b).bodyA, b);
}
TEST(JointBuilder, UseBodyB)
{
const auto b =
static_cast<BodyID>(77);
EXPECT_NE(JointBuilder<JointConf>{}.bodyB, b);
EXPECT_EQ(JointBuilder<JointConf>{}.UseBodyB(b).bodyB, b);
}
TEST(JointBuilder, UseCollideConnected)
{
const auto value = true;
EXPECT_NE(JointBuilder<JointConf>{}.collideConnected, value);
EXPECT_EQ(JointBuilder<JointConf>{}.UseCollideConnected(value).collideConnected, value);
}
TEST(Joint, ByteSize)
{
switch (sizeof(void*)) {
case 4:
break;
case 8:
EXPECT_EQ(sizeof(Joint), std::size_t(8));
break;
default:
break;
}
}
TEST(Joint, Traits)
{
EXPECT_FALSE(IsIterableV<Joint>);
EXPECT_FALSE((IsAddableV<Joint>));
EXPECT_FALSE((IsAddableV<Joint, Joint>));
EXPECT_TRUE(std::is_default_constructible_v<Joint>);
EXPECT_TRUE(std::is_nothrow_default_constructible_v<Joint>);
EXPECT_FALSE(std::is_trivially_default_constructible_v<Joint>);
EXPECT_TRUE(std::is_copy_constructible_v<Joint>);
EXPECT_FALSE(std::is_nothrow_copy_constructible_v<Joint>);
EXPECT_FALSE(std::is_trivially_copy_constructible_v<Joint>);
EXPECT_TRUE(std::is_copy_assignable_v<Joint>);
EXPECT_FALSE(std::is_nothrow_copy_assignable_v<Joint>);
EXPECT_FALSE(std::is_trivially_copy_assignable_v<Joint>);
EXPECT_TRUE(std::is_destructible_v<Joint>);
EXPECT_TRUE(std::is_nothrow_destructible_v<Joint>);
EXPECT_FALSE(std::is_trivially_destructible_v<Joint>);
EXPECT_TRUE((std::is_constructible_v<Joint, int>));
EXPECT_TRUE((std::is_constructible_v<Joint, char*>));
EXPECT_TRUE((std::is_constructible_v<Joint, test::sans_none::JointTester>));
}
TEST(Joint, DefaultConstructor)
{
const Joint joint;
EXPECT_TRUE(joint == joint);
EXPECT_FALSE(joint != joint);
EXPECT_FALSE(joint.has_value());
}
TEST(Joint, CopyAssignment)
{
const auto bodyB =
BodyID{11};
auto dst = Joint{};
auto conf = WheelJointConf{};
conf.bodyA = bodyA;
conf.bodyB = bodyB;
const auto src = Joint{conf};
ASSERT_NE(dst, src);
dst = src;
EXPECT_EQ(dst, src);
}
TEST(Joint, LimitStateToStringFF)
{
EXPECT_FALSE(equalLimitsString.empty());
EXPECT_FALSE(inactiveLimitString.empty());
EXPECT_FALSE(upperLimitsString.empty());
EXPECT_FALSE(lowerLimitsString.empty());
std::set<std::string> names;
names.insert(equalLimitsString);
names.insert(inactiveLimitString);
names.insert(upperLimitsString);
names.insert(lowerLimitsString);
EXPECT_EQ(names.size(), decltype(names.size()){4});
}
{
int foo = 5;
std::any test{foo};
std::string roo = "wow";
test = roo;
test = std::any{foo};
EXPECT_THROW(TypeCast<int>(Joint{}), std::bad_cast);
{
test::sans_none::JointTester::resetClass();
auto n = -1;
EXPECT_NO_THROW(n = TypeCast<test::sans_none::JointTester>(Joint{test::sans_none::JointTester{}}).number);
EXPECT_EQ(n, 0);
}
{
const auto joint = Joint{};
auto value = static_cast<const int*>(nullptr);
EXPECT_NO_THROW(value = TypeCast<const int>(&joint));
EXPECT_TRUE(value == nullptr);
}
{
auto joint = Joint{};
auto value = static_cast<int*>(nullptr);
EXPECT_NO_THROW(value = TypeCast<int>(&joint));
EXPECT_TRUE(value == nullptr);
}
{
const auto joint = Joint{};
EXPECT_THROW(TypeCast<int>(joint), std::bad_cast);
EXPECT_THROW(TypeCast<const int>(joint), std::bad_cast);
}
{
auto joint = Joint{};
EXPECT_THROW(TypeCast<int>(joint), std::bad_cast);
EXPECT_THROW(TypeCast<const int>(joint), std::bad_cast);
}
}
TEST(Joint, TypeCastWithSansNoneToInt)
{
constexpr auto number = 10;
const auto original = [&](){test::sans_none::JointTester v; v.number = number; return v;}();
EXPECT_EQ(original.number, number);
auto joint = Joint{original};
ASSERT_TRUE(joint.has_value());
test::sans_none::JointTester::resetClass();
EXPECT_THROW(TypeCast<int>(joint), std::bad_cast);
EXPECT_EQ(0, test::sans_none::JointTester::defaultConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyAssignmentCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveAssignmentCalled);
}
TEST(Joint, TypeCastWithSansNoneToPointer)
{
constexpr auto number = 10;
auto pointer = static_cast<test::sans_none::JointTester*>(nullptr);
const auto original = [&](){test::sans_none::JointTester v; v.number = number; return v;}();
ASSERT_EQ(original.number, number);
auto joint = Joint{original};
test::sans_none::JointTester::resetClass();
EXPECT_NO_THROW(pointer = TypeCast<test::sans_none::JointTester>(&joint));
EXPECT_EQ(0, test::sans_none::JointTester::defaultConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyAssignmentCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveAssignmentCalled);
ASSERT_TRUE(pointer != nullptr);
EXPECT_EQ(number, pointer->number);
}
TEST(Joint, AnyCastWithSansNoneToValue)
{
constexpr auto number = 10;
auto value = test::sans_none::JointTester{};
const auto original = [&](){test::sans_none::JointTester v; v.number = number; return v;}();
EXPECT_EQ(original.number, number);
auto anyObject = std::any{original};
test::sans_none::JointTester::resetClass();
EXPECT_NO_THROW(value = std::any_cast<test::sans_none::JointTester>(anyObject));
EXPECT_EQ(0, test::sans_none::JointTester::defaultConstructorCalled);
EXPECT_EQ(1, test::sans_none::JointTester::copyConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyAssignmentCalled);
EXPECT_EQ(1, test::sans_none::JointTester::moveAssignmentCalled);
EXPECT_EQ(number, value.number);
}
TEST(Joint, TypeCastWithSansNoneToValue)
{
constexpr auto number = 10;
auto value = test::sans_none::JointTester{};
const auto original = [&](){test::sans_none::JointTester v; v.number = number; return v;}();
EXPECT_EQ(original.number, number);
auto jointObject = Joint{original};
test::sans_none::JointTester::resetClass();
EXPECT_NO_THROW(value = TypeCast<test::sans_none::JointTester>(jointObject));
EXPECT_EQ(0, test::sans_none::JointTester::defaultConstructorCalled);
EXPECT_EQ(1, test::sans_none::JointTester::copyConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::moveConstructorCalled);
EXPECT_EQ(0, test::sans_none::JointTester::copyAssignmentCalled);
EXPECT_EQ(1, test::sans_none::JointTester::moveAssignmentCalled);
EXPECT_EQ(number, value.number);
}
TEST(Joint, TypeCastWithSansNone)
{
constexpr auto number = 10;
auto value = test::sans_none::JointTester{};
const auto original = [&](){test::sans_none::JointTester v; v.number = number; return v;}();
EXPECT_EQ(original.number, number);
auto joint = Joint{original};
EXPECT_NO_THROW(TypeCast<test::sans_none::JointTester&>(joint).number = 3);
EXPECT_EQ(TypeCast<const test::sans_none::JointTester&>(joint).number, 3);
EXPECT_NO_THROW(value = TypeCast<test::sans_none::JointTester>(joint));
EXPECT_EQ(value.number, 3);
EXPECT_NO_THROW(TypeCast<test::sans_none::JointTester>(&joint)->number = 4);
EXPECT_EQ(TypeCast<const test::sans_none::JointTester>(joint).number, 4);
EXPECT_TRUE(joint == joint);
EXPECT_FALSE(joint != joint);
}
TEST(Joint, ForConstantDataTypeCastIsLikeAnyCast)
{
const auto foo = Joint{[](){test::sans_none::JointTester v; v.number = 1; return v;}()};
const auto bar = std::any{[](){test::sans_none::JointTester v; v.number = 1; return v;}()};
EXPECT_TRUE(TypeCast<const test::sans_none::JointTester*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<const test::sans_none::JointTester*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<test::sans_none::JointTester*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<test::sans_none::JointTester*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<const test::sans_none::JointTester>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<const test::sans_none::JointTester>(&bar) != nullptr);
EXPECT_TRUE(TypeCast<test::sans_none::JointTester>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<test::sans_none::JointTester>(&bar) != nullptr);
}
TEST(Joint, ForMutableDataTypeCastIsLikeAnyCast)
{
auto foo = Joint{[](){test::sans_none::JointTester v; v.number = 1; return v;}()};
auto bar = std::any{[](){test::sans_none::JointTester v; v.number = 1; return v;}()};
EXPECT_TRUE(TypeCast<const test::sans_none::JointTester*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<const test::sans_none::JointTester*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<test::sans_none::JointTester*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<test::sans_none::JointTester*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<const test::sans_none::JointTester>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<const test::sans_none::JointTester>(&bar) != nullptr);
EXPECT_TRUE(TypeCast<test::sans_none::JointTester>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<test::sans_none::JointTester>(&bar) != nullptr);
}
{
}
{
}
TEST(Joint, SetMotorSpeedThrows)
{
auto joint = Joint{};
EXPECT_THROW(
SetMotorSpeed(joint, 1_rpm), std::invalid_argument);
}
TEST(Joint, SetMaxMotorForceThrows)
{
auto joint = Joint{};
}
TEST(Joint, SetMaxMotorTorqueThrows)
{
auto joint = Joint{};
}
TEST(Joint, SetLinearLimitsThrows)
{
auto joint = Joint{};
}
TEST(Joint, SetAngularLimitsThrows)
{
auto joint = Joint{};
}
TEST(Joint, IsLimitEnabledThrows)
{
}
TEST(Joint, EnableLimitThrows)
{
auto joint = Joint{};
EXPECT_THROW(
EnableLimit(joint,
true), std::invalid_argument);
EXPECT_THROW(
EnableLimit(joint,
false), std::invalid_argument);
}
TEST(Joint, IsMotorEnabledThrows)
{
auto joint = Joint{};
}
TEST(Joint, EnableMotorThrows)
{
auto joint = Joint{};
EXPECT_THROW(
EnableMotor(joint,
true), std::invalid_argument);
EXPECT_THROW(
EnableMotor(joint,
false), std::invalid_argument);
}
TEST(Joint, GetLimitStateThrows)
{
auto joint = Joint{};
}
TEST(Joint, EqualsOperator)
{
const auto j0 = Joint(WheelJointConf());
EXPECT_TRUE(j0 == j0);
{
auto conf = WheelJointConf{};
conf.localAnchorA =
Length2{1.2_m, -3_m};
const auto j1 = Joint(conf);
EXPECT_TRUE(j1 == j1);
EXPECT_FALSE(j0 == j1);
}
{
auto conf = WheelJointConf{};
conf.localAnchorB =
Length2{1.2_m, -3_m};
const auto j1 = Joint(conf);
EXPECT_TRUE(j1 == j1);
EXPECT_FALSE(j0 == j1);
}
{
auto conf = WheelJointConf{};
conf.motorSpeed = 0.12_rpm;
const auto j1 = Joint(conf);
EXPECT_TRUE(j1 == j1);
EXPECT_FALSE(j0 == j1);
}
}
TEST(Joint, NotEqualsOperator)
{
const auto j0 = Joint(WheelJointConf());
EXPECT_FALSE(j0 != j0);
{
auto conf = WheelJointConf{};
conf.frequency = 13_Hz;
const auto j1 = Joint(conf);
EXPECT_FALSE(j1 != j1);
EXPECT_TRUE(j0 != j1);
}
}
Definition of the JointConf class and closely related code.
Definition of the Joint class and closely related code.
Definitions of miscellaneous template related code.
Definition of the WheelJointConf class and closely related code.
detail::angular_momentum AngularMomentum
Angular momentum quantity.
Definition: Units.hpp:390
bool IsMotorEnabled(const Joint &object)
Gets the specified joint's motor property value if it supports one.
Definition: Joint.cpp:563
void SetLinearLimits(Joint &object, Length lower, Length upper)
Definition: Joint.cpp:499
constexpr Momentum2 GetLinearReaction(const DistanceJointConf &object) noexcept
Gets the current linear reaction for the given configuration.
Definition: DistanceJointConf.hpp:175
BodyID GetBodyB(const Joint &object) noexcept
Gets the second body attached to this joint.
Definition: Joint.hpp:295
BodyType GetType(const Body &body) noexcept
Gets the type of this body.
Definition: Body.hpp:748
std::add_pointer_t< std::add_const_t< T > > TypeCast(const Joint *value) noexcept
Converts the given joint into its current configuration value.
Definition: Joint.hpp:439
BodyID GetBodyA(const Joint &object) noexcept
Gets the first body attached to this joint.
Definition: Joint.hpp:290
void SetMaxMotorTorque(Joint &object, Torque value)
Sets the given joint's max motor torque if its type supports that.
Definition: Joint.cpp:366
void SetMaxMotorForce(Joint &object, Force value)
Sets the given joint's max motor force if its type supports that.
Definition: Joint.cpp:344
void SetMotorSpeed(Joint &object, AngularVelocity value)
Sets the given joint's motor speed if its type supports that.
Definition: Joint.cpp:272
LimitState GetLimitState(const Joint &object)
Definition: Joint.cpp:634
bool IsLimitEnabled(const Joint &object)
Gets the specified joint's limit property if it supports one.
Definition: Joint.cpp:537
void SetAngularLimits(Joint &object, Angle lower, Angle upper)
Sets the joint limits.
Definition: Joint.cpp:527
bool GetCollideConnected(const Joint &object) noexcept
Gets collide connected.
Definition: Joint.hpp:300
void EnableMotor(Joint &object, bool value)
Enables the specified joint's motor property if it supports one.
Definition: Joint.cpp:578
void EnableLimit(Joint &object, bool value)
Enables the specified joint's limit property if it supports one.
Definition: Joint.cpp:549
constexpr AngularMomentum GetAngularReaction(const DistanceJointConf &) noexcept
Gets the current angular reaction for the given configuration.
Definition: DistanceJointConf.hpp:182
Definition: ArrayList.hpp:43
Vector2< Momentum > Momentum2
2-element vector of Momentum quantities.
Definition: Vector2.hpp:76
constexpr auto InvalidBodyID
Invalid body ID value.
Definition: BodyID.hpp:50
Vector2< Length > Length2
2-element vector of Length quantities.
Definition: Vector2.hpp:51
@ e_inactiveLimit
Inactive limit.
@ e_equalLimits
Equal limit.
@ e_atUpperLimit
At-upper limit.
@ e_atLowerLimit
At-lower limit.
detail::IndexingNamedType< BodyCounter, struct BodyIdentifier > BodyID
Body identifier.
Definition: BodyID.hpp:44
const char * ToString(LimitState val) noexcept
Provides a human readable C-style string uniquely identifying the given limit state.
Definition: LimitState.cpp:27