Improve error reporting of sensorized objects.

Also remove duplication of element name and id from most error messages.

PiperOrigin-RevId: 628065116
Change-Id: Idd962fbab7aeba09e3a70c6c9d044b23db94cf23
This commit is contained in:
Yuval Tassa
2024-04-25 07:12:26 -07:00
committed by Copybara-Service
parent cbb048ff00
commit 027c26a153
4 changed files with 187 additions and 217 deletions
+97 -169
View File
@@ -61,7 +61,7 @@ static void checksize(double* size, mjtGeom type, mjCBase* object, const char* n
// plane: handle infinite // plane: handle infinite
if (type==mjGEOM_PLANE) { if (type==mjGEOM_PLANE) {
if (size[2]<=0) { if (size[2]<=0) {
throw mjCError(object, "plane size(3) must be positive in object '%s' (id = %d)", name, id); throw mjCError(object, "plane size(3) must be positive");
} }
} }
@@ -69,7 +69,7 @@ static void checksize(double* size, mjtGeom type, mjCBase* object, const char* n
else { else {
for (int i=0; i<mjGEOMINFO[type]; i++) { for (int i=0; i<mjGEOMINFO[type]; i++) {
if (size[i]<=0) { if (size[i]<=0) {
throw mjCError(object, "sizes must be positive in object '%s' (id = %d)", name, id); throw mjCError(object, "size %d must be positive in geom", "", i);
} }
} }
} }
@@ -159,14 +159,14 @@ mjCError::mjCError(const mjCBase* obj, const char* msg, const char* str, int pos
mju::strcat_arr(message, temp); mju::strcat_arr(message, temp);
} }
// append info from mjCBase object // append info from mjCBase element
if (obj) { if (obj) {
// with or without xml position // with or without xml position
if (!obj->info.empty()) { if (!obj->info.empty()) {
mju::sprintf_arr(temp, "Object name = %s, id = %d, %s", mju::sprintf_arr(temp, "Element name '%s', id %d, %s",
obj->name.c_str(), obj->id, obj->info.c_str()); obj->name.c_str(), obj->id, obj->info.c_str());
} else { } else {
mju::sprintf_arr(temp, "Object name = %s, id = %d", obj->name.c_str(), obj->id); mju::sprintf_arr(temp, "Element name '%s', id %d", obj->name.c_str(), obj->id);
} }
// append to message // append to message
@@ -1244,8 +1244,7 @@ void mjCBody::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_body) { if (userdata_.size() > model->nuser_body) {
throw mjCError(this, "user has more values than nuser_body in body '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_body in body");
name.c_str(), id);
} }
userdata_.resize(model->nuser_body); userdata_.resize(model->nuser_body);
@@ -1627,17 +1626,14 @@ int mjCJoint::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_jnt) { if (userdata_.size() > model->nuser_jnt) {
throw mjCError(this, "user has more values than nuser_jnt in joint '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_jnt in joint");
name.c_str(), id);
} }
userdata_.resize(model->nuser_jnt); userdata_.resize(model->nuser_jnt);
// check springdamper // check springdamper
if (springdamper[0] || springdamper[1]) { if (springdamper[0] || springdamper[1]) {
if (springdamper[0]<=0 || springdamper[1]<=0) { if (springdamper[0]<=0 || springdamper[1]<=0) {
throw mjCError(this, throw mjCError(this, "when defined, springdamper values must be positive in joint");
"when defined, springdamper values must be positive in joint '%s' (id = %d)",
name.c_str(), id);
} }
} }
@@ -1655,12 +1651,10 @@ int mjCJoint::Compile(void) {
if (is_limited()) { if (is_limited()) {
// check data // check data
if (range[0]>=range[1] && type!=mjJNT_BALL) { if (range[0]>=range[1] && type!=mjJNT_BALL) {
throw mjCError(this, throw mjCError(this, "range[0] should be smaller than range[1] in joint");
"range[0] should be smaller than range[1] in joint '%s' (id = %d)",
name.c_str(), id);
} }
if (range[0] && type==mjJNT_BALL) { if (range[0] && type==mjJNT_BALL) {
throw mjCError(this, "range[0] should be 0 in ball joint '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "range[0] should be 0 in ball joint");
} }
// convert limits to radians // convert limits to radians
@@ -1688,9 +1682,7 @@ int mjCJoint::Compile(void) {
if (is_actfrclimited()) { if (is_actfrclimited()) {
// check data // check data
if (actfrcrange[0]>=actfrcrange[1]) { if (actfrcrange[0]>=actfrcrange[1]) {
throw mjCError(this, throw mjCError(this, "actfrcrange[0] should be smaller than actfrcrange[1] in joint");
"actfrcrange[0] should be smaller than actfrcrange[1] in joint '%s' (id = %d)",
name.c_str(), id);
} }
} }
@@ -1714,13 +1706,12 @@ int mjCJoint::Compile(void) {
// normalize axis, check norm // normalize axis, check norm
if (mjuu_normvec(axis, 3)<mjEPS) { if (mjuu_normvec(axis, 3)<mjEPS) {
throw mjCError(this, "axis too small in joint '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "axis too small in joint");
} }
// check data // check data
if (type==mjJNT_FREE && limited == mjLIMITED_TRUE) { if (type==mjJNT_FREE && limited == mjLIMITED_TRUE) {
throw mjCError(this, throw mjCError(this, "limits should not be defined in free joint");
"limits should not be defined in free joint '%s' (id = %d)", name.c_str(), id);
} }
// compute local position // compute local position
@@ -1851,7 +1842,7 @@ double mjCGeom::GetVolume(void) {
// get from mesh // get from mesh
if (type==mjGEOM_MESH || type==mjGEOM_SDF) { if (type==mjGEOM_MESH || type==mjGEOM_SDF) {
if (mesh->id<0 || !((std::size_t) mesh->id <= model->meshes.size())) { if (mesh->id<0 || !((std::size_t) mesh->id <= model->meshes.size())) {
throw mjCError(this, "invalid mesh id in mesh geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid mesh id in mesh geom");
} }
return mesh->GetVolumeRef(typeinertia); return mesh->GetVolumeRef(typeinertia);
@@ -1904,7 +1895,7 @@ void mjCGeom::SetInertia(void) {
// get from mesh // get from mesh
if (type==mjGEOM_MESH || type==mjGEOM_SDF) { if (type==mjGEOM_MESH || type==mjGEOM_SDF) {
if (mesh->id<0 || !((std::size_t) mesh->id <= model->meshes.size())) { if (mesh->id<0 || !((std::size_t) mesh->id <= model->meshes.size())) {
throw mjCError(this, "invalid mesh id in mesh geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid mesh id in mesh geom");
} }
double* boxsz = mesh->GetInertiaBoxPtr(typeinertia); double* boxsz = mesh->GetInertiaBoxPtr(typeinertia);
@@ -2190,12 +2181,12 @@ void mjCGeom::Compile(void) {
// check type // check type
if (type<0 || type>=mjNGEOMTYPES) { if (type<0 || type>=mjNGEOMTYPES) {
throw mjCError(this, "invalid type in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid type in geom");
} }
// check condim // check condim
if (condim!=1 && condim!=3 && condim!=4 && condim!=6) { if (condim!=1 && condim!=3 && condim!=4 && condim!=6) {
throw mjCError(this, "invalid condim in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid condim in geom");
} }
// check mesh // check mesh
@@ -2210,8 +2201,7 @@ void mjCGeom::Compile(void) {
// plane only allowed in static bodies // plane only allowed in static bodies
if (type==mjGEOM_PLANE && body->weldid!=0) { if (type==mjGEOM_PLANE && body->weldid!=0) {
throw mjCError(this, "plane only allowed in static bodies: geom '%s' (id = %d)", throw mjCError(this, "plane only allowed in static bodies");
name.c_str(), id);
} }
// check if can collide // check if can collide
@@ -2227,16 +2217,12 @@ void mjCGeom::Compile(void) {
type!=mjGEOM_CYLINDER && type!=mjGEOM_CYLINDER &&
type!=mjGEOM_ELLIPSOID && type!=mjGEOM_ELLIPSOID &&
type!=mjGEOM_BOX) { type!=mjGEOM_BOX) {
throw mjCError(this, throw mjCError(this, "fromto requires capsule, cylinder, box or ellipsoid in geom");
"fromto requires capsule, cylinder, box or ellipsoid in geom '%s' (id = %d)",
name.c_str(), id);
} }
// make sure pos is not defined; cannot use mjuu_defined because default is (0,0,0) // make sure pos is not defined; cannot use mjuu_defined because default is (0,0,0)
if (pos[0] || pos[1] || pos[2]) { if (pos[0] || pos[1] || pos[2]) {
throw mjCError(this, throw mjCError(this, "both pos and fromto defined in geom");
"both pos and fromto defined in geom '%s' (id = %d)",
name.c_str(), id);
} }
// size[1] = length (for capsule and cylinder) // size[1] = length (for capsule and cylinder)
@@ -2247,7 +2233,7 @@ void mjCGeom::Compile(void) {
}; };
size[1] = mjuu_normvec(vec, 3)/2; size[1] = mjuu_normvec(vec, 3)/2;
if (size[1]<mjEPS) { if (size[1]<mjEPS) {
throw mjCError(this, "fromto points too close in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "fromto points too close in geom");
} }
// adjust size for ellipsoid and box // adjust size for ellipsoid and box
@@ -2277,7 +2263,7 @@ void mjCGeom::Compile(void) {
if (mesh) { if (mesh) {
// check for inapplicable fromto // check for inapplicable fromto
if (mjuu_defined(fromto[0])) { if (mjuu_defined(fromto[0])) {
throw mjCError(this, "fromto cannot be used with mesh geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "fromto cannot be used with mesh geom");
} }
// save reference in case this is not an mjGEOM_MESH // save reference in case this is not an mjGEOM_MESH
@@ -2319,7 +2305,7 @@ void mjCGeom::Compile(void) {
for (double s : size) { for (double s : size) {
if (std::isnan(s)) { if (std::isnan(s)) {
throw mjCError(this, "nan size in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "nan size in geom");
} }
} }
// compute aabb // compute aabb
@@ -2343,8 +2329,7 @@ void mjCGeom::Compile(void) {
// check for negative values // check for negative values
if (mass_<0 || inertia[0]<0 || inertia[1]<0 || inertia[2]<0 || density<0) if (mass_<0 || inertia[0]<0 || inertia[1]<0 || inertia[2]<0 || density<0)
throw mjCError(this, "mass, inertia or density are negative in geom '%s' (id = %d)", throw mjCError(this, "mass, inertia or density are negative in geom");
name.c_str(), id);
} }
// fluid-interaction coefficients, requires computed inertia and mass // fluid-interaction coefficients, requires computed inertia and mass
@@ -2356,8 +2341,7 @@ void mjCGeom::Compile(void) {
if (plugin.active) { if (plugin.active) {
if (plugin_name.empty() && plugin_instance_name.empty()) { if (plugin_name.empty() && plugin_instance_name.empty()) {
throw mjCError( throw mjCError(
this, "neither 'plugin' nor 'instance' is specified for geom '%s', (id = %d)", this, "neither 'plugin' nor 'instance' is specified for geom");
name.c_str(), id);
} }
mjCPlugin* plugin_instance = static_cast<mjCPlugin*>(plugin.instance); mjCPlugin* plugin_instance = static_cast<mjCPlugin*>(plugin.instance);
@@ -2453,20 +2437,18 @@ void mjCSite::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_site) { if (userdata_.size() > model->nuser_site) {
throw mjCError(this, "user has more values than nuser_site in site '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_site in site");
name.c_str(), id);
} }
userdata_.resize(model->nuser_site); userdata_.resize(model->nuser_site);
// check type // check type
if (type<0 || type>=mjNGEOMTYPES) { if (type<0 || type>=mjNGEOMTYPES) {
throw mjCError(this, "invalid type in site '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid type in site");
} }
// do not allow meshes, hfields and planes // do not allow meshes, hfields and planes
if (type==mjGEOM_MESH || type==mjGEOM_HFIELD || type==mjGEOM_PLANE) { if (type==mjGEOM_MESH || type==mjGEOM_HFIELD || type==mjGEOM_PLANE) {
throw mjCError(this, "meshes, hfields and planes not allowed in site '%s' (id = %d)", throw mjCError(this, "meshes, hfields and planes not allowed in site");
name.c_str(), id);
} }
// 'fromto': compute pos, quat, size // 'fromto': compute pos, quat, size
@@ -2476,14 +2458,12 @@ void mjCSite::Compile(void) {
type!=mjGEOM_CYLINDER && type!=mjGEOM_CYLINDER &&
type!=mjGEOM_ELLIPSOID && type!=mjGEOM_ELLIPSOID &&
type!=mjGEOM_BOX) { type!=mjGEOM_BOX) {
throw mjCError(this, throw mjCError(this, "fromto requires capsule, cylinder, box or ellipsoid in geom");
"fromto requires capsule, cylinder, box or ellipsoid in geom '%s' (id = %d)",
name.c_str(), id);
} }
// make sure pos is not defined; cannot use mjuu_defined because default is (0,0,0) // make sure pos is not defined; cannot use mjuu_defined because default is (0,0,0)
if (pos[0] || pos[1] || pos[2]) { if (pos[0] || pos[1] || pos[2]) {
throw mjCError(this, "both pos and fromto defined in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "both pos and fromto defined in geom");
} }
// size[1] = length (for capsule and cylinder) // size[1] = length (for capsule and cylinder)
@@ -2494,7 +2474,7 @@ void mjCSite::Compile(void) {
}; };
size[1] = mjuu_normvec(vec, 3)/2; size[1] = mjuu_normvec(vec, 3)/2;
if (size[1]<mjEPS) { if (size[1]<mjEPS) {
throw mjCError(this, "fromto points too close in geom '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "fromto points too close in geom");
} }
// adjust size for ellipsoid and box // adjust size for ellipsoid and box
@@ -2618,8 +2598,7 @@ void mjCCamera::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_cam) { if (userdata_.size() > model->nuser_cam) {
throw mjCError(this, "user has more values than nuser_cam in camera '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_cam in camera");
name.c_str(), id);
} }
userdata_.resize(model->nuser_cam); userdata_.resize(model->nuser_cam);
@@ -2643,7 +2622,7 @@ void mjCCamera::Compile(void) {
if (tb) { if (tb) {
targetbodyid = tb->id; targetbodyid = tb->id;
} else { } else {
throw mjCError(this, "unknown target body in camera '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "unknown target body in camera");
} }
} }
@@ -2656,14 +2635,12 @@ void mjCCamera::Compile(void) {
// check that specs are not duplicated // check that specs are not duplicated
if ((principal_length[0] && principal_pixel[0]) || if ((principal_length[0] && principal_pixel[0]) ||
(principal_length[1] && principal_pixel[1])) { (principal_length[1] && principal_pixel[1])) {
throw mjCError(this, "principal length duplicated in camera '%s' (id = %d)", throw mjCError(this, "principal length duplicated in camera");
name.c_str(), id);
} }
if ((focal_length[0] && focal_pixel[0]) || if ((focal_length[0] && focal_pixel[0]) ||
(focal_length[1] && focal_pixel[1])) { (focal_length[1] && focal_pixel[1])) {
throw mjCError(this, "focal length duplicated in camera '%s' (id = %d)", throw mjCError(this, "focal length duplicated in camera");
name.c_str(), id);
} }
// compute number of pixels per unit length // compute number of pixels per unit length
@@ -2774,7 +2751,7 @@ void mjCLight::Compile(void) {
// normalize direction, make sure it is not zero // normalize direction, make sure it is not zero
if (mjuu_normvec(dir, 3)<mjMINVAL) { if (mjuu_normvec(dir, 3)<mjMINVAL) {
throw mjCError(this, "zero direction in light '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "zero direction in light");
} }
// get targetbodyid // get targetbodyid
@@ -2783,7 +2760,7 @@ void mjCLight::Compile(void) {
if (tb) { if (tb) {
targetbodyid = tb->id; targetbodyid = tb->id;
} else { } else {
throw mjCError(this, "unknown target body in light '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "unknown target body in light");
} }
} }
} }
@@ -2976,8 +2953,7 @@ void mjCHField::Compile(const mjVFS* vfs) {
// check size parameters // check size parameters
for (int i=0; i<4; i++) for (int i=0; i<4; i++)
if (size[i]<=0) if (size[i]<=0)
throw mjCError(this, throw mjCError(this, "size parameter is not positive in hfield");
"size parameter is not positive in hfield '%s' (id = %d)", name.c_str(), id);
// remove path from file if necessary // remove path from file if necessary
if (model->strippath) { if (model->strippath) {
@@ -2988,8 +2964,7 @@ void mjCHField::Compile(const mjVFS* vfs) {
if (!file_.empty()) { if (!file_.empty()) {
// make sure hfield was not already specified manually // make sure hfield was not already specified manually
if (nrow || ncol || !data.empty()) { if (nrow || ncol || !data.empty()) {
throw mjCError(this, throw mjCError(this, "hfield specified from file and manually");
"hfield '%s' (id = %d) specified from file and manually", name.c_str(), id);
} }
std::string asset_type = GetAssetContentType(file_, content_type_); std::string asset_type = GetAssetContentType(file_, content_type_);
@@ -3021,7 +2996,7 @@ void mjCHField::Compile(const mjVFS* vfs) {
// make sure hfield was specified (from file or manually) // make sure hfield was specified (from file or manually)
if (nrow<1 || ncol<1 || data.empty()) { if (nrow<1 || ncol<1 || data.empty()) {
throw mjCError(this, "hfield '%s' (id = %d) not specified", name.c_str(), id); throw mjCError(this, "hfield not specified");
} }
// set elevation data to [0-1] range // set elevation data to [0-1] range
@@ -3530,9 +3505,7 @@ void mjCTexture::Load2D(string filename, const mjVFS* vfs) {
void mjCTexture::LoadCubeSingle(string filename, const mjVFS* vfs) { void mjCTexture::LoadCubeSingle(string filename, const mjVFS* vfs) {
// check gridsize // check gridsize
if (gridsize[0]<1 || gridsize[1]<1 || gridsize[0]*gridsize[1]>12) { if (gridsize[0]<1 || gridsize[1]<1 || gridsize[0]*gridsize[1]>12) {
throw mjCError(this, throw mjCError(this, "gridsize must be non-zero and no more than 12 squares in texture");
"gridsize must be non-zero and no more than 12 squares in texture '%s' (id %d)",
(const char*)name.c_str(), id);
} }
// load PNG or custom // load PNG or custom
@@ -3590,8 +3563,7 @@ void mjCTexture::LoadCubeSingle(string filename, const mjVFS* vfs) {
} else if (gridlayout[k]=='B') { } else if (gridlayout[k]=='B') {
i = 5; i = 5;
} else if (gridlayout[k]!='.') } else if (gridlayout[k]!='.')
throw mjCError(this, "gridlayout symbol is not among '.RLUDFB' in texture '%s' (id %d)", throw mjCError(this, "gridlayout symbol is not among '.RLUDFB' in texture");
(const char*)file_.c_str(), id);
// load if specified // load if specified
if (i>=0) { if (i>=0) {
@@ -3660,9 +3632,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
height = 6*width; height = 6*width;
rgb.assign(3*width*height, 0); rgb.assign(3*width*height, 0);
if (rgb.empty()) { if (rgb.empty()) {
throw mjCError(this, throw mjCError(this, "Could not allocate memory for texture");
"Could not allocate memory for texture '%s' (id %d)",
(const char*)name.c_str(), id);
} }
} }
@@ -3706,9 +3676,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
if (builtin!=mjBUILTIN_NONE) { if (builtin!=mjBUILTIN_NONE) {
// check size // check size
if (width<1 || height<1) { if (width<1 || height<1) {
throw mjCError(this, throw mjCError(this, "Invalid width or height of builtin texture");
"Invalid width or height of builtin texture '%s' (id %d)",
(const char*)name.c_str(), id);
} }
// adjust height of cube texture // adjust height of cube texture
@@ -3719,9 +3687,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
// allocate data // allocate data
rgb.assign(3*width*height, 0); rgb.assign(3*width*height, 0);
if (rgb.empty()) { if (rgb.empty()) {
throw mjCError(this, throw mjCError(this, "Could not allocate memory for texture");
"Could not allocate memory for texture '%s' (id %d)",
(const char*)name.c_str(), id);
} }
// dispatch // dispatch
@@ -3755,8 +3721,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
// 2D not allowed // 2D not allowed
if (type==mjTEXTURE_2D) { if (type==mjTEXTURE_2D) {
throw mjCError(this, throw mjCError(this,
"Cannot load 2D texture from separate files, texture '%s' (id %d)", "Cannot load 2D texture from separate files, texture");
(const char*)name.c_str(), id);
} }
// at least one cubefile must be defined // at least one cubefile must be defined
@@ -3769,8 +3734,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
} }
if (!defined) { if (!defined) {
throw mjCError(this, throw mjCError(this,
"No cubefiles_ defined in cube or skybox texture '%s' (id %d)", "No cubefiles_ defined in cube or skybox texture");
(const char*)name.c_str(), id);
} }
// only cube and skybox // only cube and skybox
@@ -3779,8 +3743,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
// make sure someone allocated data; SHOULD NOT OCCUR // make sure someone allocated data; SHOULD NOT OCCUR
if (rgb.empty()) { if (rgb.empty()) {
throw mjCError(this, throw mjCError(this, "texture '%s' (id %d) was not specified", name.c_str(), id);
"texture '%s' (id %d) was not specified", (const char*)name.c_str(), id);
} }
} }
@@ -3979,7 +3942,7 @@ void mjCPair::Compile(void) {
// check condim // check condim
if (condim!=1 && condim!=3 && condim!=4 && condim!=6) { if (condim!=1 && condim!=3 && condim!=4 && condim!=6) {
throw mjCError(this, "invalid condim in collision %d", "", id); throw mjCError(this, "invalid condim in contact pair");
} }
// find geoms // find geoms
@@ -4289,7 +4252,7 @@ void mjCEquality::ResolveReferences(const mjCModel* m) {
} else if (type==mjEQ_FLEX) { } else if (type==mjEQ_FLEX) {
objtype = mjOBJ_FLEX; objtype = mjOBJ_FLEX;
} else { } else {
throw mjCError(this, "invalid type in equality constraint '%s' (id = %d)'", name.c_str(), id); throw mjCError(this, "invalid type in equality constraint");
} }
// find object 1, get id // find object 1, get id
@@ -4311,8 +4274,7 @@ void mjCEquality::ResolveReferences(const mjCModel* m) {
// object 2 unspecified: set to -1 // object 2 unspecified: set to -1
else { else {
if (objtype==mjOBJ_GEOM) { if (objtype==mjOBJ_GEOM) {
throw mjCError(this, "both geom are required in equality constraint '%s' (id = %d)", throw mjCError(this, "both geom are required in equality constraint");
name.c_str(), id);
} else { } else {
obj2id = -1; obj2id = -1;
px2 = 0; px2 = 0;
@@ -4335,8 +4297,7 @@ void mjCEquality::ResolveReferences(const mjCModel* m) {
jt2 = (px2 ? ((mjCJoint*)px2)->type : mjJNT_HINGE); jt2 = (px2 ? ((mjCJoint*)px2)->type : mjJNT_HINGE);
if ((jt1!=mjJNT_HINGE && jt1!=mjJNT_SLIDE) || if ((jt1!=mjJNT_HINGE && jt1!=mjJNT_SLIDE) ||
(jt2!=mjJNT_HINGE && jt2!=mjJNT_SLIDE)) { (jt2!=mjJNT_HINGE && jt2!=mjJNT_SLIDE)) {
throw mjCError(this, "only HINGE and SLIDE joint allowed in constraint '%s' (id = %d)", throw mjCError(this, "only HINGE and SLIDE joint allowed in constraint");
name.c_str(), id);
} }
} }
} }
@@ -4568,8 +4529,7 @@ void mjCTendon::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_tendon) { if (userdata_.size() > model->nuser_tendon) {
throw mjCError(this, "user has more values than nuser_tendon in tendon '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_tendon in tendon");
name.c_str(), id);
} }
userdata_.resize(model->nuser_tendon); userdata_.resize(model->nuser_tendon);
@@ -4677,12 +4637,12 @@ void mjCTendon::Compile(void) {
// check limits // check limits
if (range[0]>=range[1] && is_limited()) { if (range[0]>=range[1] && is_limited()) {
throw mjCError(this, "invalid limits in tendon '%s (id = %d)'", name.c_str(), id); throw mjCError(this, "invalid limits in tendon");
} }
// check springlength // check springlength
if (springlength[0] > springlength[1]) { if (springlength[0] > springlength[1]) {
throw mjCError(this, "invalid springlength in tendon '%s (id = %d)'", name.c_str(), id); throw mjCError(this, "invalid springlength in tendon");
} }
} }
@@ -4987,7 +4947,7 @@ void mjCActuator::ResolveReferences(const mjCModel* m) {
break; break;
default: default:
throw mjCError(this, "invalid transmission type in actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid transmission type in actuator");
} }
// assign and check // assign and check
@@ -5014,7 +4974,7 @@ void mjCActuator::Compile(void) {
// check for missing target name // check for missing target name
if (target_.empty()) { if (target_.empty()) {
throw mjCError(this, throw mjCError(this,
"missing transmission target for actuator '%s' (id = %d)", name.c_str(), id); "missing transmission target for actuator");
} }
// find transmission target in object arrays // find transmission target in object arrays
@@ -5033,7 +4993,7 @@ void mjCActuator::Compile(void) {
range = actrange; range = actrange;
} else { } else {
throw mjCError(this, "inheritrange only available for position " throw mjCError(this, "inheritrange only available for position "
"and intvelocity actuators '%s' (id = %d)", name.c_str(), id); "and intvelocity actuators");
} }
const double* target_range; const double* target_range;
@@ -5041,7 +5001,7 @@ void mjCActuator::Compile(void) {
mjCJoint* pjnt = (mjCJoint*) ptarget; mjCJoint* pjnt = (mjCJoint*) ptarget;
if (pjnt->spec.type != mjJNT_HINGE && pjnt->spec.type != mjJNT_SLIDE) { if (pjnt->spec.type != mjJNT_HINGE && pjnt->spec.type != mjJNT_SLIDE) {
throw mjCError(this, "inheritrange can only be used with hinge and slide joints, " throw mjCError(this, "inheritrange can only be used with hinge and slide joints, "
"actuator '%s' (id = %d)", name.c_str(), id); "actuator");
} }
target_range = pjnt->get_range(); target_range = pjnt->get_range();
} else if (trntype == mjTRN_TENDON) { } else if (trntype == mjTRN_TENDON) {
@@ -5049,7 +5009,7 @@ void mjCActuator::Compile(void) {
target_range = pten->get_range(); target_range = pten->get_range();
} else { } else {
throw mjCError(this, "inheritrange can only be used with joint and tendon transmission, " throw mjCError(this, "inheritrange can only be used with joint and tendon transmission, "
"actuator '%s' (id = %d)", name.c_str(), id); "actuator");
} }
if (target_range[0] == target_range[1]) { if (target_range[0] == target_range[1]) {
@@ -5080,29 +5040,27 @@ void mjCActuator::Compile(void) {
// check limits // check limits
if (forcerange[0]>=forcerange[1] && is_forcelimited()) { if (forcerange[0]>=forcerange[1] && is_forcelimited()) {
throw mjCError(this, "invalid force range for actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid force range for actuator");
} }
if (ctrlrange[0]>=ctrlrange[1] && is_ctrllimited()) { if (ctrlrange[0]>=ctrlrange[1] && is_ctrllimited()) {
throw mjCError(this, "invalid control range for actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid control range for actuator");
} }
if (actrange[0]>=actrange[1] && is_actlimited()) { if (actrange[0]>=actrange[1] && is_actlimited()) {
throw mjCError(this, "invalid actrange for actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid actrange for actuator");
} }
if (is_actlimited() && dyntype == mjDYN_NONE) { if (is_actlimited() && dyntype == mjDYN_NONE) {
throw mjCError(this, "actrange specified but dyntype is 'none' in actuator '%s' (id = %d)", throw mjCError(this, "actrange specified but dyntype is 'none' in actuator");
name.c_str(), id);
} }
// check and set actdim // check and set actdim
if (actdim > 1 && dyntype != mjDYN_USER) { if (actdim > 1 && dyntype != mjDYN_USER) {
throw mjCError(this, "actdim > 1 is only allowed for dyntype 'user' in actuator '%s' (id = %d)", throw mjCError(this, "actdim > 1 is only allowed for dyntype 'user' in actuator");
name.c_str(), id);
} }
if (actdim == 1 && dyntype == mjDYN_NONE) { if (actdim == 1 && dyntype == mjDYN_NONE) {
throw mjCError(this, "invalid actdim 1 in stateless actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid actdim 1 in stateless actuator");
} }
if (actdim == 0 && dyntype != mjDYN_NONE) { if (actdim == 0 && dyntype != mjDYN_NONE) {
throw mjCError(this, "invalid actdim 0 in stateful actuator '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid actdim 0 in stateful actuator");
} }
// set actdim // set actdim
@@ -5127,12 +5085,12 @@ void mjCActuator::Compile(void) {
// range // range
if (prm[0]>=prm[1]) { if (prm[0]>=prm[1]) {
throw mjCError(this, "range[0]<range[1] required in muscle '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "range[0]<range[1] required in muscle");
} }
// lmin<1<lmax // lmin<1<lmax
if (prm[4]>=1 || prm[5]<=1) { if (prm[4]>=1 || prm[5]<=1) {
throw mjCError(this, "lmin<1<lmax required in muscle '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "lmin<1<lmax required in muscle");
} }
// scale, vmax, fpmax, fvmax>0 // scale, vmax, fpmax, fvmax>0
@@ -5255,17 +5213,13 @@ void mjCSensor::ResolveReferences(const mjCModel* m) {
if (objtype!=mjOBJ_UNKNOWN) { if (objtype!=mjOBJ_UNKNOWN) {
// check for missing object name // check for missing object name
if (objname_.empty()) { if (objname_.empty()) {
throw mjCError(this, throw mjCError(this, "missing name of sensorized object in sensor");
"missing name of sensorized object in sensor '%s' (id = %d)",
name.c_str(), id);
} }
// find name // find name
obj = m->FindObject(objtype, objname_); obj = m->FindObject(objtype, objname_);
if (!obj) { if (!obj) {
throw mjCError(this, throw mjCError(this, "unrecognized name '%s' of sensorized object", objname_.c_str());
"unrecognized name of sensorized object in sensor '%s' (id = %d)",
name.c_str(), id);
} }
// if geom mark it as non visual // if geom mark it as non visual
@@ -5275,32 +5229,27 @@ void mjCSensor::ResolveReferences(const mjCModel* m) {
// get sensorized object id // get sensorized object id
} else if (type != mjSENS_CLOCK && type != mjSENS_PLUGIN && type != mjSENS_USER) { } else if (type != mjSENS_CLOCK && type != mjSENS_PLUGIN && type != mjSENS_USER) {
throw mjCError(this, "invalid type in sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "invalid type in sensor");
} }
// get refid from reftype and refname // get refid from reftype and refname
if (reftype!=mjOBJ_UNKNOWN) { if (reftype!=mjOBJ_UNKNOWN) {
// check for missing object name // check for missing object name
if (refname_.empty()) { if (refname_.empty()) {
throw mjCError(this, throw mjCError(this, "missing name of reference frame object in sensor");
"missing name of reference frame object in sensor '%s' (id = %d)",
name.c_str(), id);
} }
// find name // find name
ref = m->FindObject(reftype, refname_); ref = m->FindObject(reftype, refname_);
if (!ref) { if (!ref) {
throw mjCError(this, throw mjCError(this, "unrecognized name '%s' of reference frame object", refname_.c_str());
"unrecognized name of reference frame object in sensor '%s' (id = %d)",
name.c_str(), id);
} }
// must be attached to object with spatial frame // must be attached to object with spatial frame
if (reftype!=mjOBJ_BODY && reftype!=mjOBJ_XBODY && if (reftype!=mjOBJ_BODY && reftype!=mjOBJ_XBODY &&
reftype!=mjOBJ_GEOM && reftype!=mjOBJ_SITE && reftype!=mjOBJ_CAMERA) { reftype!=mjOBJ_GEOM && reftype!=mjOBJ_SITE && reftype!=mjOBJ_CAMERA) {
throw mjCError(this, throw mjCError(this,
"reference frame object must be (x)body, geom, site or camera:" "reference frame object must be (x)body, geom, site or camera in sensor");
" sensor '%s' (id = %d)", name.c_str(), id);
} }
// get sensorized object id // get sensorized object id
@@ -5316,19 +5265,18 @@ void mjCSensor::Compile(void) {
// resize userdata // resize userdata
if (userdata_.size() > model->nuser_sensor) { if (userdata_.size() > model->nuser_sensor) {
throw mjCError(this, "user has more values than nuser_sensor in sensor '%s' (id = %d)", throw mjCError(this, "user has more values than nuser_sensor in sensor");
name.c_str(), id);
} }
userdata_.resize(model->nuser_sensor); userdata_.resize(model->nuser_sensor);
// require non-negative noise // require non-negative noise
if (noise<0) { if (noise<0) {
throw mjCError(this, "negative noise in sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "negative noise in sensor");
} }
// require non-negative cutoff // require non-negative cutoff
if (cutoff<0) { if (cutoff<0) {
throw mjCError(this, "negative cutoff in sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "negative cutoff in sensor");
} }
// Find referenced object // Find referenced object
@@ -5347,8 +5295,7 @@ void mjCSensor::Compile(void) {
case mjSENS_CAMPROJECTION: case mjSENS_CAMPROJECTION:
// must be attached to site // must be attached to site
if (objtype!=mjOBJ_SITE) { if (objtype!=mjOBJ_SITE) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to site: sensor");
"sensor must be attached to site: sensor '%s' (id = %d)", name.c_str(), id);
} }
// set dim and datatype // set dim and datatype
@@ -5376,9 +5323,7 @@ void mjCSensor::Compile(void) {
if (type==mjSENS_CAMPROJECTION) { if (type==mjSENS_CAMPROJECTION) {
mjCCamera* camref = (mjCCamera*)ref; mjCCamera* camref = (mjCCamera*)ref;
if (!camref->resolution[0] || !camref->resolution[1]) { if (!camref->resolution[0] || !camref->resolution[1]) {
throw mjCError(this, throw mjCError(this, "camera projection sensor requires camera resolution");
"camera projection sensor requires camera resolution '%s' (id = %d)",
name.c_str(), id);
} }
} }
break; break;
@@ -5388,14 +5333,12 @@ void mjCSensor::Compile(void) {
case mjSENS_JOINTACTFRC: case mjSENS_JOINTACTFRC:
// must be attached to joint // must be attached to joint
if (objtype!=mjOBJ_JOINT) { if (objtype!=mjOBJ_JOINT) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to joint: sensor");
"sensor must be attached to joint: sensor '%s' (id = %d)", name.c_str(), id);
} }
// make sure joint is slide or hinge // make sure joint is slide or hinge
if (((mjCJoint*)obj)->type!=mjJNT_SLIDE && ((mjCJoint*)obj)->type!=mjJNT_HINGE) { if (((mjCJoint*)obj)->type!=mjJNT_SLIDE && ((mjCJoint*)obj)->type!=mjJNT_HINGE) {
throw mjCError(this, throw mjCError(this, "joint must be slide or hinge in sensor");
"joint must be slide or hinge in sensor '%s' (id = %d)", name.c_str(), id);
} }
// set // set
@@ -5414,8 +5357,7 @@ void mjCSensor::Compile(void) {
case mjSENS_TENDONVEL: case mjSENS_TENDONVEL:
// must be attached to tendon // must be attached to tendon
if (objtype!=mjOBJ_TENDON) { if (objtype!=mjOBJ_TENDON) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to tendon: sensor");
"sensor must be attached to tendon: sensor '%s' (id = %d)", name.c_str(), id);
} }
// set // set
@@ -5433,8 +5375,7 @@ void mjCSensor::Compile(void) {
case mjSENS_ACTUATORFRC: case mjSENS_ACTUATORFRC:
// must be attached to actuator // must be attached to actuator
if (objtype!=mjOBJ_ACTUATOR) { if (objtype!=mjOBJ_ACTUATOR) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to actuator: sensor");
"sensor must be attached to actuator: sensor '%s' (id = %d)", name.c_str(), id);
} }
// set // set
@@ -5453,14 +5394,12 @@ void mjCSensor::Compile(void) {
case mjSENS_BALLANGVEL: case mjSENS_BALLANGVEL:
// must be attached to joint // must be attached to joint
if (objtype!=mjOBJ_JOINT) { if (objtype!=mjOBJ_JOINT) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to joint: sensor");
"sensor must be attached to joint: sensor '%s' (id = %d)", name.c_str(), id);
} }
// make sure joint is ball // make sure joint is ball
if (((mjCJoint*)obj)->type!=mjJNT_BALL) { if (((mjCJoint*)obj)->type!=mjJNT_BALL) {
throw mjCError(this, throw mjCError(this, "joint must be ball in sensor");
"joint must be ball in sensor '%s' (id = %d)", name.c_str(), id);
} }
// set // set
@@ -5480,13 +5419,12 @@ void mjCSensor::Compile(void) {
case mjSENS_JOINTLIMITFRC: case mjSENS_JOINTLIMITFRC:
// must be attached to joint // must be attached to joint
if (objtype!=mjOBJ_JOINT) { if (objtype!=mjOBJ_JOINT) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to joint: sensor");
"sensor must be attached to joint: sensor '%s' (id = %d)", name.c_str(), id);
} }
// make sure joint has limit // make sure joint has limit
if (!((mjCJoint*)obj)->is_limited()) { if (!((mjCJoint*)obj)->is_limited()) {
throw mjCError(this, "joint must be limited in sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "joint must be limited in sensor");
} }
// set // set
@@ -5506,13 +5444,12 @@ void mjCSensor::Compile(void) {
case mjSENS_TENDONLIMITFRC: case mjSENS_TENDONLIMITFRC:
// must be attached to tendon // must be attached to tendon
if (objtype!=mjOBJ_TENDON) { if (objtype!=mjOBJ_TENDON) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to tendon: sensor");
"sensor must be attached to tendon: sensor '%s' (id = %d)", name.c_str(), id);
} }
// make sure tendon has limit // make sure tendon has limit
if (!((mjCTendon*)obj)->is_limited()) { if (!((mjCTendon*)obj)->is_limited()) {
throw mjCError(this, "tendon must be limited in sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "tendon must be limited in sensor");
} }
// set // set
@@ -5539,9 +5476,7 @@ void mjCSensor::Compile(void) {
// must be attached to object with spatial frame // must be attached to object with spatial frame
if (objtype!=mjOBJ_BODY && objtype!=mjOBJ_XBODY && if (objtype!=mjOBJ_BODY && objtype!=mjOBJ_XBODY &&
objtype!=mjOBJ_GEOM && objtype!=mjOBJ_SITE && objtype!=mjOBJ_CAMERA) { objtype!=mjOBJ_GEOM && objtype!=mjOBJ_SITE && objtype!=mjOBJ_CAMERA) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to (x)body, geom, site or camera");
"sensor must be attached to (x)body, geom, site or camera:"
" sensor '%s' (id = %d)", name.c_str(), id);
} }
// set dim // set dim
@@ -5575,8 +5510,7 @@ void mjCSensor::Compile(void) {
case mjSENS_SUBTREEANGMOM: case mjSENS_SUBTREEANGMOM:
// must be attached to body // must be attached to body
if (objtype!=mjOBJ_BODY) { if (objtype!=mjOBJ_BODY) {
throw mjCError(this, throw mjCError(this, "sensor must be attached to body: sensor");
"sensor must be attached to body: sensor '%s' (id = %d)", name.c_str(), id);
} }
// set // set
@@ -5598,18 +5532,16 @@ void mjCSensor::Compile(void) {
case mjSENS_USER: case mjSENS_USER:
// check for negative dim // check for negative dim
if (dim<0) { if (dim<0) {
throw mjCError(this, "sensor dim must be positive: sensor '%s' (id = %d)", name.c_str(), id); throw mjCError(this, "sensor dim must be positive in sensor");
} }
// make sure dim is consistent with datatype // make sure dim is consistent with datatype
if (datatype==mjDATATYPE_AXIS && dim!=3) { if (datatype==mjDATATYPE_AXIS && dim!=3) {
throw mjCError(this, throw mjCError(this,
"datatype AXIS requires dim=3 in sensor '%s' (id = %d)", name.c_str(), id); "datatype AXIS requires dim=3 in sensor");
} }
if (datatype==mjDATATYPE_QUATERNION && dim!=4) { if (datatype==mjDATATYPE_QUATERNION && dim!=4) {
throw mjCError(this, throw mjCError(this, "datatype QUATERNION requires dim=4 in sensor");
"datatype QUATERNION requires dim=4 in sensor '%s' (id = %d)",
name.c_str(), id);
} }
break; break;
@@ -5618,9 +5550,7 @@ void mjCSensor::Compile(void) {
datatype = mjDATATYPE_REAL; // no noise added to plugin sensors, this attribute is unused datatype = mjDATATYPE_REAL; // no noise added to plugin sensors, this attribute is unused
if (plugin_name.empty() && plugin_instance_name.empty()) { if (plugin_name.empty() && plugin_instance_name.empty()) {
throw mjCError( throw mjCError(this, "neither 'plugin' nor 'instance' is specified for sensor");
this, "neither 'plugin' nor 'instance' is specified for sensor '%s', (id = %d)",
name.c_str(), id);
} }
// resolve plugin instance, or create one if using the "plugin" attribute shortcut // resolve plugin instance, or create one if using the "plugin" attribute shortcut
@@ -5643,9 +5573,7 @@ void mjCSensor::Compile(void) {
// check cutoff for incompatible data types // check cutoff for incompatible data types
if (cutoff>0 && (datatype==mjDATATYPE_AXIS || datatype==mjDATATYPE_QUATERNION)) { if (cutoff>0 && (datatype==mjDATATYPE_AXIS || datatype==mjDATATYPE_QUATERNION)) {
throw mjCError(this, throw mjCError(this, "cutoff applied to axis or quaternion datatype in sensor");
"cutoff applied to axis or quaternion datatype in sensor '%s' (id = %d)",
name.c_str(), id);
} }
} }
+24 -24
View File
@@ -1344,7 +1344,7 @@ void mjXReader::OneFlex(XMLElement* elem, mjsFlex* pflex) {
} }
// write error info // write error info
mjs_setString(pflex->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pflex->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1414,7 +1414,7 @@ void mjXReader::OneMesh(XMLElement* elem, mjsMesh* pmesh) {
} }
// write error info // write error info
mjs_setString(pmesh->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pmesh->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1502,7 +1502,7 @@ void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin) {
mjs_setFloat(pskin->bindquat, bindquat.data(), bindquat.size()); mjs_setFloat(pskin->bindquat, bindquat.data(), bindquat.size());
// write error info // write error info
mjs_setString(pskin->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pskin->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1535,7 +1535,7 @@ void mjXReader::OneMaterial(XMLElement* elem, mjsMaterial* pmat) {
ReadAttr(elem, "rgba", 4, pmat->rgba, text); ReadAttr(elem, "rgba", 4, pmat->rgba, text);
// write error info // write error info
mjs_setString(pmat->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pmat->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1585,7 +1585,7 @@ void mjXReader::OneJoint(XMLElement* elem, mjsJoint* pjoint) {
} }
// write error info // write error info
mjs_setString(pjoint->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pjoint->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1660,7 +1660,7 @@ void mjXReader::OneGeom(XMLElement* elem, mjsGeom* pgeom) {
} }
// write error info // write error info
mjs_setString(pgeom->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pgeom->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1697,7 +1697,7 @@ void mjXReader::OneSite(XMLElement* elem, mjsSite* site) {
} }
// write error info // write error info
mjs_setString(site->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(site->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1751,7 +1751,7 @@ void mjXReader::OneCamera(XMLElement* elem, mjsCamera* pcam) {
mjs_setDouble(pcam->userdata, userdata.data(), userdata.size()); mjs_setDouble(pcam->userdata, userdata.data(), userdata.size());
// write error info // write error info
mjs_setString(pcam->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pcam->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1794,7 +1794,7 @@ void mjXReader::OneLight(XMLElement* elem, mjsLight* plight) {
ReadAttr(elem, "specular", 3, plight->specular, text); ReadAttr(elem, "specular", 3, plight->specular, text);
// write error info // write error info
mjs_setString(plight->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(plight->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1829,7 +1829,7 @@ void mjXReader::OnePair(XMLElement* elem, mjsPair* ppair) {
ReadAttr(elem, "friction", 5, ppair->friction, text, false, false); ReadAttr(elem, "friction", 5, ppair->friction, text, false, false);
// write error info // write error info
mjs_setString(ppair->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(ppair->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1907,7 +1907,7 @@ void mjXReader::OneEquality(XMLElement* elem, mjsEquality* pequality) {
ReadAttr(elem, "solimp", mjNIMP, pequality->solimp, text, false, false); ReadAttr(elem, "solimp", mjNIMP, pequality->solimp, text, false, false);
// write error info // write error info
mjs_setString(pequality->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pequality->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -1951,7 +1951,7 @@ void mjXReader::OneTendon(XMLElement* elem, mjsTendon* pten) {
} }
// write error info // write error info
mjs_setString(pten->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pten->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -2241,7 +2241,7 @@ void mjXReader::OneActuator(XMLElement* elem, mjsActuator* pact) {
} }
// write info // write info
mjs_setString(pact->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pact->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
} }
@@ -2762,7 +2762,7 @@ void mjXReader::Extension(XMLElement* section) {
} }
string name; string name;
mjsPlugin* p = mjs_addPlugin(model); mjsPlugin* p = mjs_addPlugin(model);
mjs_setString(p->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(p->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
ReadAttrTxt(child, "name", name, /* required = */ true); ReadAttrTxt(child, "name", name, /* required = */ true);
mjs_setString(p->name, name.c_str()); mjs_setString(p->name, name.c_str());
if (!p->name) { if (!p->name) {
@@ -2803,7 +2803,7 @@ void mjXReader::Custom(XMLElement* section) {
mjsNumeric* pnum = mjs_addNumeric(model); mjsNumeric* pnum = mjs_addNumeric(model);
// write error info // write error info
mjs_setString(pnum->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pnum->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
ReadAttrTxt(elem, "name", elname, true); ReadAttrTxt(elem, "name", elname, true);
@@ -2834,7 +2834,7 @@ void mjXReader::Custom(XMLElement* section) {
mjsText* pte = mjs_addText(model); mjsText* pte = mjs_addText(model);
// write error info // write error info
mjs_setString(pte->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pte->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
ReadAttrTxt(elem, "name", elname, true); ReadAttrTxt(elem, "name", elname, true);
@@ -2854,7 +2854,7 @@ void mjXReader::Custom(XMLElement* section) {
mjsTuple* ptu = mjs_addTuple(model); mjsTuple* ptu = mjs_addTuple(model);
// write error info // write error info
mjs_setString(ptu->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(ptu->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
ReadAttrTxt(elem, "name", elname, true); ReadAttrTxt(elem, "name", elname, true);
@@ -3061,7 +3061,7 @@ void mjXReader::Asset(XMLElement* section) {
mjsTexture* ptex = mjs_addTexture(model); mjsTexture* ptex = mjs_addTexture(model);
// write error info // write error info
mjs_setString(ptex->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(ptex->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
if (MapValue(elem, "type", &n, texture_map, texture_sz)) { if (MapValue(elem, "type", &n, texture_map, texture_sz)) {
@@ -3150,7 +3150,7 @@ void mjXReader::Asset(XMLElement* section) {
mjsHField* phf = mjs_addHField(model); mjsHField* phf = mjs_addHField(model);
// write error info // write error info
mjs_setString(phf->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(phf->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
string name, content_type; string name, content_type;
@@ -3353,7 +3353,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
// create frame // create frame
mjsFrame* pframe = mjs_addFrame(pbody, frame); mjsFrame* pframe = mjs_addFrame(pbody, frame);
mjs_setString(pframe->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pframe->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
mjs_setDefault(pframe->element, childdef ? childdef : def); mjs_setDefault(pframe->element, childdef ? childdef : def);
// read attributes // read attributes
@@ -3386,7 +3386,7 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
// create child body // create child body
mjsBody* pchild = mjs_addBody(pbody, childdef); mjsBody* pchild = mjs_addBody(pbody, childdef);
mjs_setString(pchild->info, mjs_setString(pchild->info,
std::string("line = " + std::to_string(elem->GetLineNum())).c_str()); std::string("line " + std::to_string(elem->GetLineNum())).c_str());
// read attributes // read attributes
std::string name, childclass; std::string name, childclass;
@@ -3460,7 +3460,7 @@ void mjXReader::Contact(XMLElement* section) {
string exname, exbody1, exbody2; string exname, exbody1, exbody2;
// write error info // write error info
mjs_setString(pexclude->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(pexclude->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// read name and body names // read name and body names
if (ReadAttrTxt(elem, "name", exname)) { if (ReadAttrTxt(elem, "name", exname)) {
@@ -3596,7 +3596,7 @@ void mjXReader::Tendon(XMLElement* section) {
throw mjXError(sub, "unknown wrap type"); // SHOULD NOT OCCUR throw mjXError(sub, "unknown wrap type"); // SHOULD NOT OCCUR
} }
mjs_setString(pwrap->info, ("line = " + std::to_string(sub->GetLineNum())).c_str()); mjs_setString(pwrap->info, ("line " + std::to_string(sub->GetLineNum())).c_str());
// advance to next sub-element // advance to next sub-element
sub = NextSiblingElement(sub); sub = NextSiblingElement(sub);
@@ -3935,7 +3935,7 @@ void mjXReader::Sensor(XMLElement* section) {
} }
// write info // write info
mjs_setString(psen->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); mjs_setString(psen->info, ("line " + std::to_string(elem->GetLineNum())).c_str());
// advance to next element // advance to next element
elem = NextSiblingElement(elem); elem = NextSiblingElement(elem);
+64 -22
View File
@@ -543,8 +543,9 @@ TEST_F(RelativeFrameSensorParsingTest, BadRefName) {
)"; )";
std::array<char, 1024> error; std::array<char, 1024> error;
LoadModelFromString(xml, error.data(), error.size()); LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(error.data(), HasSubstr("unrecognized name of reference frame")); EXPECT_THAT(error.data(),
EXPECT_THAT(error.data(), HasSubstr("line = 8")); HasSubstr("unrecognized name 'wrong_name' of reference frame"));
EXPECT_THAT(error.data(), HasSubstr("line 8"));
} }
TEST_F(RelativeFrameSensorParsingTest, BadRefType) { TEST_F(RelativeFrameSensorParsingTest, BadRefType) {
@@ -563,7 +564,48 @@ TEST_F(RelativeFrameSensorParsingTest, BadRefType) {
std::array<char, 1024> error; std::array<char, 1024> error;
LoadModelFromString(xml, error.data(), error.size()); LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(error.data(), HasSubstr("reference frame object must be")); EXPECT_THAT(error.data(), HasSubstr("reference frame object must be"));
EXPECT_THAT(error.data(), HasSubstr("line = 8")); EXPECT_THAT(error.data(), HasSubstr("line 8"));
}
TEST_F(RelativeFrameSensorParsingTest, BadObjName) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<site name="a"/>
</worldbody>
<sensor>
<framepos name="tom" objtype="site" objname="alessio" reftype="site" refname="a"/>
</sensor>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(),
HasSubstr("unrecognized name 'alessio' of sensorized object"));
EXPECT_THAT(error.data(), HasSubstr("name 'tom'"));
EXPECT_THAT(error.data(), HasSubstr("line 7"));
}
TEST_F(RelativeFrameSensorParsingTest, BadObjRefName) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<site name="a"/>
</worldbody>
<sensor>
<framepos name="tom" objtype="site" objname="a" reftype="site" refname="alessio"/>
</sensor>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(
error.data(),
HasSubstr("unrecognized name 'alessio' of reference frame object"));
EXPECT_THAT(error.data(), HasSubstr("name 'tom'"));
EXPECT_THAT(error.data(), HasSubstr("line 7"));
} }
// ------------- sensor compilation -------------------------------------------- // ------------- sensor compilation --------------------------------------------
@@ -710,7 +752,7 @@ TEST_F(MjCGeomTest, NanSize) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, testing::IsNull()); ASSERT_THAT(model, testing::IsNull());
ASSERT_THAT(error.data(), HasSubstr("nan")); ASSERT_THAT(error.data(), HasSubstr("nan"));
EXPECT_THAT(error.data(), HasSubstr("line = 5")); EXPECT_THAT(error.data(), HasSubstr("line 5"));
} }
// ------------- test height fields -------------------------------------------- // ------------- test height fields --------------------------------------------
@@ -785,7 +827,7 @@ TEST_F(CameraSpecTest, FovyLimits) {
mjModel* m = LoadModelFromString(xml, error.data(), error.size()); mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data(); EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("fovy too large")); EXPECT_THAT(error.data(), HasSubstr("fovy too large"));
EXPECT_THAT(error.data(), HasSubstr("line = 6")); EXPECT_THAT(error.data(), HasSubstr("line 6"));
mj_deleteModel(m); mj_deleteModel(m);
} }
@@ -1071,7 +1113,7 @@ TEST_F(ActRangeTest, ActRangeBad) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actrange")); EXPECT_THAT(error.data(), HasSubstr("invalid actrange"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
TEST_F(ActRangeTest, ActRangeUndefined) { TEST_F(ActRangeTest, ActRangeUndefined) {
@@ -1092,7 +1134,7 @@ TEST_F(ActRangeTest, ActRangeUndefined) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actrange")); EXPECT_THAT(error.data(), HasSubstr("invalid actrange"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
TEST_F(ActRangeTest, ActRangeNoDyntype) { TEST_F(ActRangeTest, ActRangeNoDyntype) {
@@ -1199,7 +1241,7 @@ TEST_F(ActDimTest, NonzeroNotAllowedInStateless) {
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actdim 1 in stateless")); EXPECT_THAT(error.data(), HasSubstr("invalid actdim 1 in stateless"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
TEST_F(ActDimTest, ZeroNotAllowedInStateful) { TEST_F(ActDimTest, ZeroNotAllowedInStateful) {
@@ -1221,7 +1263,7 @@ TEST_F(ActDimTest, ZeroNotAllowedInStateful) {
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actdim 0 in stateful")); EXPECT_THAT(error.data(), HasSubstr("invalid actdim 0 in stateful"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
// ------------- test nuser_xxx fields ----------------------------------------- // ------------- test nuser_xxx fields -----------------------------------------
@@ -1241,7 +1283,7 @@ TEST_F(UserDataTest, NBodyTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_body")); EXPECT_THAT(error.data(), HasSubstr("nuser_body"));
EXPECT_THAT(error.data(), HasSubstr("line = 5")); EXPECT_THAT(error.data(), HasSubstr("line 5"));
} }
TEST_F(UserDataTest, NJointTooSmall) { TEST_F(UserDataTest, NJointTooSmall) {
@@ -1260,7 +1302,7 @@ TEST_F(UserDataTest, NJointTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_jnt")); EXPECT_THAT(error.data(), HasSubstr("nuser_jnt"));
EXPECT_THAT(error.data(), HasSubstr("line = 7")); EXPECT_THAT(error.data(), HasSubstr("line 7"));
} }
TEST_F(UserDataTest, NGeomTooSmall) { TEST_F(UserDataTest, NGeomTooSmall) {
@@ -1276,7 +1318,7 @@ TEST_F(UserDataTest, NGeomTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_geom")); EXPECT_THAT(error.data(), HasSubstr("nuser_geom"));
EXPECT_THAT(error.data(), HasSubstr("line = 5")); EXPECT_THAT(error.data(), HasSubstr("line 5"));
} }
TEST_F(UserDataTest, NSiteTooSmall) { TEST_F(UserDataTest, NSiteTooSmall) {
@@ -1292,7 +1334,7 @@ TEST_F(UserDataTest, NSiteTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_site")); EXPECT_THAT(error.data(), HasSubstr("nuser_site"));
EXPECT_THAT(error.data(), HasSubstr("line = 5")); EXPECT_THAT(error.data(), HasSubstr("line 5"));
} }
TEST_F(UserDataTest, NCameraTooSmall) { TEST_F(UserDataTest, NCameraTooSmall) {
@@ -1308,7 +1350,7 @@ TEST_F(UserDataTest, NCameraTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_cam")); EXPECT_THAT(error.data(), HasSubstr("nuser_cam"));
EXPECT_THAT(error.data(), HasSubstr("line = 5")); EXPECT_THAT(error.data(), HasSubstr("line 5"));
} }
TEST_F(UserDataTest, NTendonTooSmall) { TEST_F(UserDataTest, NTendonTooSmall) {
@@ -1331,7 +1373,7 @@ TEST_F(UserDataTest, NTendonTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_tendon")); EXPECT_THAT(error.data(), HasSubstr("nuser_tendon"));
EXPECT_THAT(error.data(), HasSubstr("line = 9")); EXPECT_THAT(error.data(), HasSubstr("line 9"));
} }
TEST_F(UserDataTest, NActuatorTooSmall) { TEST_F(UserDataTest, NActuatorTooSmall) {
@@ -1353,7 +1395,7 @@ TEST_F(UserDataTest, NActuatorTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_actuator")); EXPECT_THAT(error.data(), HasSubstr("nuser_actuator"));
EXPECT_THAT(error.data(), HasSubstr("line = 11")); EXPECT_THAT(error.data(), HasSubstr("line 11"));
} }
TEST_F(UserDataTest, NSensorTooSmall) { TEST_F(UserDataTest, NSensorTooSmall) {
@@ -1372,7 +1414,7 @@ TEST_F(UserDataTest, NSensorTooSmall) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_sensor")); EXPECT_THAT(error.data(), HasSubstr("nuser_sensor"));
EXPECT_THAT(error.data(), HasSubstr("line = 8")); EXPECT_THAT(error.data(), HasSubstr("line 8"));
} }
// ------------- test for auto parsing of *limited fields ---------------------- // ------------- test for auto parsing of *limited fields ----------------------
@@ -1415,7 +1457,7 @@ TEST_F(LimitedTest, ErrorIfLimitedMissingOnJoint) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("limited")); EXPECT_THAT(error.data(), HasSubstr("limited"));
EXPECT_THAT(error.data(), HasSubstr("line = 6")); EXPECT_THAT(error.data(), HasSubstr("line 6"));
} }
TEST_F(LimitedTest, ExplicitLimitedFalseIsOk) { TEST_F(LimitedTest, ExplicitLimitedFalseIsOk) {
@@ -1465,7 +1507,7 @@ TEST_F(LimitedTest, ErrorIfLimitedMissingOnTendon) {
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("limited")); EXPECT_THAT(error.data(), HasSubstr("limited"));
EXPECT_THAT(error.data(), HasSubstr("tendon")); EXPECT_THAT(error.data(), HasSubstr("tendon"));
EXPECT_THAT(error.data(), HasSubstr("line = 13")); EXPECT_THAT(error.data(), HasSubstr("line 13"));
} }
TEST_F(LimitedTest, ErrorIfForceLimitedMissingOnActuator) { TEST_F(LimitedTest, ErrorIfForceLimitedMissingOnActuator) {
@@ -1490,7 +1532,7 @@ TEST_F(LimitedTest, ErrorIfForceLimitedMissingOnActuator) {
EXPECT_THAT(error.data(), HasSubstr("forcelimited")); EXPECT_THAT(error.data(), HasSubstr("forcelimited"));
EXPECT_THAT(error.data(), HasSubstr("forcerange")); EXPECT_THAT(error.data(), HasSubstr("forcerange"));
EXPECT_THAT(error.data(), HasSubstr("actuator")); EXPECT_THAT(error.data(), HasSubstr("actuator"));
EXPECT_THAT(error.data(), HasSubstr("line = 11")); EXPECT_THAT(error.data(), HasSubstr("line 11"));
} }
// ------------- tests for tendon ---------------------------------------------- // ------------- tests for tendon ----------------------------------------------
@@ -1518,7 +1560,7 @@ TEST_F(TendonTest, SiteBetweenPulleyNotAllowed) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, IsNull()); EXPECT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("needs a neighbor that is not a pulley")); EXPECT_THAT(error.data(), HasSubstr("needs a neighbor that is not a pulley"));
EXPECT_THAT(error.data(), HasSubstr("line = 9")); EXPECT_THAT(error.data(), HasSubstr("line 9"));
} }
// ------------- tests for tendon springrange ---------------------------------- // ------------- tests for tendon springrange ----------------------------------
@@ -1573,7 +1615,7 @@ TEST_F(SpringrangeTest, InvalidRange) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid springlength in tendon")); EXPECT_THAT(error.data(), HasSubstr("invalid springlength in tendon"));
EXPECT_THAT(error.data(), HasSubstr("line = 9")); EXPECT_THAT(error.data(), HasSubstr("line 9"));
} }
// ------------- test frame ---------------------------------------------------- // ------------- test frame ----------------------------------------------------
+2 -2
View File
@@ -1289,7 +1289,7 @@ TEST_F(ActuatorParseTest, DamperRequiresControlRange) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid control range")); EXPECT_THAT(error.data(), HasSubstr("invalid control range"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
TEST_F(ActuatorParseTest, DamperPositiveControlRange) { TEST_F(ActuatorParseTest, DamperPositiveControlRange) {
@@ -1505,7 +1505,7 @@ TEST_F(ActuatorParseTest, IntvelocityNoActrangeThrowsError) {
mjModel* model = LoadModelFromString(xml, error.data(), error.size()); mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()); ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actrange for actuator")); EXPECT_THAT(error.data(), HasSubstr("invalid actrange for actuator"));
EXPECT_THAT(error.data(), HasSubstr("line = 10")); EXPECT_THAT(error.data(), HasSubstr("line 10"));
} }
TEST_F(ActuatorParseTest, IntvelocityDefaultsPropagate) { TEST_F(ActuatorParseTest, IntvelocityDefaultsPropagate) {