Files
Mujoco_WASM/test/xml/xml_native_reader_test.cc
T
Alessio Quaglino f3453cf87f Stricter parsing of XML array attributes.
PiperOrigin-RevId: 451456510
Change-Id: I2556d4365762378261c04d3c9f1942166fbd156e
2022-05-27 12:51:02 -07:00

300 lines
8.0 KiB
C++

// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Tests for xml/xml_native_reader.cc.
#include <array>
#include <cstddef>
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mujoco.h>
#include "test/fixture.h"
namespace mujoco {
namespace {
using ::testing::HasSubstr;
using ::testing::IsNull;
using UserDataTest = MujocoTest;
TEST_F(UserDataTest, InvalidNUserBody) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_body="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_body"));
}
TEST_F(UserDataTest, InvalidNUserJoint) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_jnt="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_jnt"));
}
TEST_F(UserDataTest, InvalidNUserGeom) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_geom="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_geom"));
}
TEST_F(UserDataTest, InvalidNUserSite) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_site="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_site"));
}
TEST_F(UserDataTest, InvalidNUserCamera) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_cam="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_cam"));
}
TEST_F(UserDataTest, InvalidNUserTendon) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_tendon="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_tendon"));
}
TEST_F(UserDataTest, InvalidNUserActuator) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_actuator="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_actuator"));
}
TEST_F(UserDataTest, InvalidNUserSensor) {
static constexpr char xml[] = R"(
<mujoco>
<size nuser_sensor="-2"/>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("nuser_sensor"));
}
TEST_F(UserDataTest, InvalidArrayElement) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1" axisangle="1.0 0.0 0.0 [[1]]"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("problem reading attribute 'axisangle'"));
}
TEST_F(UserDataTest, InvalidArrayLength) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1" axisangle="1 0 0 0 asd"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("has too much data"));
}
TEST_F(UserDataTest, InvalidNumber) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1" axisangle="1 0.1.2.3"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("problem reading attribute"));
}
TEST_F(UserDataTest, AllowsSpaces) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1" axisangle="1 0 0 0 "/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, Not(IsNull()));
mj_deleteModel(model);
}
// ------------- test relative frame sensor parsing ----------------------------
using RelativeFrameSensorParsingTest = MujocoTest;
TEST_F(RelativeFrameSensorParsingTest, RefNameButNoType) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<site name="reference"/>
<body name="sensorized"/>
</worldbody>
<sensor>
<framepos objname="sensorized" objtype="body" refname="reference"/>
</sensor>
</mujoco>
)";
std::array<char, 1024> error;
LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(error.data(), HasSubstr("but reftype is missing"));
}
TEST_F(RelativeFrameSensorParsingTest, RefTypeButNoName) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<site name="reference"/>
<body name="sensorized"/>
</worldbody>
<sensor>
<framepos objname="sensorized" objtype="body" reftype="site"/>
</sensor>
</mujoco>
)";
std::array<char, 1024> error;
LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'refname'"));
}
// ------------- test actlimited parsing ---------------------------------------
using ActuatorTest = MujocoTest;
TEST_F(ActuatorTest, InvalidActlimited) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<joint name="hinge"/>
<geom size="1"/>
</body>
</worldbody>
<actuator>
<motor joint="hinge" actlimited="invalid" actrange="-1 1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("unrecognized attribute"));
}
TEST_F(ActuatorTest, IncompleteActlimited) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<joint name="hinge"/>
<geom size="1"/>
</body>
</worldbody>
<actuator>
<general joint="hinge" actlimited="true" actrange="-1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(error.data(), HasSubstr("attribute 'actrange' does not have enough data"));
}
TEST_F(ActuatorTest, ReadsByte) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<joint name="hinge"/>
<geom size="1"/>
</body>
</worldbody>
<actuator>
<general joint="hinge" dyntype="filter" actlimited="true" actrange="-1 1"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, Not(IsNull()));
EXPECT_EQ(*(model->actuator_actlimited), (mjtByte)(1 & 0xFF));
mj_deleteModel(model);
}
} // namespace
} // namespace mujoco