C++ Core: Add base class per sensor/actuator type

Adding base classes for UPM sensors and actuators.

Signed-off-by: Noel Eck <noel.eck@intel.com>
This commit is contained in:
Noel Eck
2017-06-08 13:50:09 -07:00
parent b55501e327
commit 0223cd2b85
184 changed files with 4462 additions and 1099 deletions

View File

@ -18,10 +18,29 @@ target_link_libraries(json_tests GTest::GTest GTest::Main)
target_include_directories(json_tests PRIVATE "${UPM_COMMON_HEADER_DIRS}/")
gtest_add_tests(json_tests "" AUTO)
# Unit tests - core library
add_executable(core_tests
core/iUpmObject_tests.cxx
core/iSensortType_tests.cxx
core/iActuatorType_tests.cxx
core/iServoActuator_tests.cxx
core/sensortype_example.json
core/actuatortype_example.json)
configure_file(core/sensortype_example.json sensortype_example.json COPYONLY)
configure_file(core/actuatortype_example.json actuatortype_example.json COPYONLY)
target_link_libraries(core_tests core GTest::GTest GTest::Main)
gtest_add_tests(core_tests "" AUTO)
# Add a custom target for unit tests
add_custom_target(tests-unit ALL
DEPENDS
utilities_tests
json_tests
core_tests
COMMENT "UPM unit test collection")

View File

@ -0,0 +1,39 @@
{
"Library": "core_tests",
"Description": "Unit test JSON example",
"Sensor Class": {
"ServoTest": {
"Name": "This is a name",
"Description": "This is a description",
"Aliases": ["Alias blibbity", "Alias blah"],
"Categories": ["servo"],
"Connections": ["uart"],
"Project Type": ["industrial", "commercial"],
"Manufacturers": ["Omega"],
"Commands" : {
"axis0": {
"unit": "degrees",
"min" : 0.0,
"max" : 180.0,
"accuracy" : 1.0
}
},
"Specifications": {
"Vsource": {
"unit": "V",
"min": 5.0,
"max": 5.0
},
"Operating Temperature": {
"unit": "°C",
"min": -40,
"max": 85
}
}
},
"Urls": {
"Product Pages": ["http://www.omega.com/pptst/RH-USB.html"],
"Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"]
}
}
}

View File

@ -0,0 +1,41 @@
#include "gtest/gtest.h"
#include "iUpmObject.hpp"
#include "iActuatorType.hpp"
#include "iServoActuator.hpp"
#include "external/json/json.hpp"
#include <vector>
/* Interfaces test fixture */
class iActuatorType_unit : public ::testing::Test, public virtual upm::iActuatorType
{
protected:
/* One-time setup logic if needed */
iActuatorType_unit()
{
this->initFromJsonLibDesc("./actuatortype_example.json");
}
/* One-time tear-down logic if needed */
virtual ~iActuatorType_unit() {}
/* Per-test setup logic if needed */
virtual void SetUp() {}
/* Per-test tear-down logic if needed */
virtual void TearDown() {}
};
TEST_F(iActuatorType_unit, test_commands_deserialize)
{
/* Deserialize the JSON to a map of commands */
std::map<std::string, upm::ActuatorSink<float>> commands =
LibraryJson()["Sensor Class"]["ServoTest"]["Commands"];
ASSERT_EQ(1, commands.size());
ASSERT_TRUE(commands.find("axis0") != commands.end());
ASSERT_EQ("degrees", commands["axis0"].unit);
ASSERT_EQ(0.0, commands["axis0"].min);
ASSERT_EQ(180.0, commands["axis0"].max);
}

View File

@ -0,0 +1,70 @@
#include "gtest/gtest.h"
#include "iUpmObject.hpp"
#include "iSensorType.hpp"
#include "iTemperatureSensor.hpp"
#include "external/json/json.hpp"
#include <vector>
/* Interfaces test fixture */
class iSensorType_unit : public ::testing::Test, public virtual upm::iSensorType
{
protected:
/* One-time setup logic if needed */
iSensorType_unit()
{
this->initFromJsonLibDesc("./sensortype_example.json");
}
/* One-time tear-down logic if needed */
virtual ~iSensorType_unit() {}
/* Per-test setup logic if needed */
virtual void SetUp() {}
/* Per-test tear-down logic if needed */
virtual void TearDown() {}
//TestSensorClass& obj;
};
TEST_F(iSensorType_unit, test_sources_deserialize)
{
/* Deserialize the JSON to a map of sources */
std::map<std::string, upm::SensorSource<float>> sources =
LibraryJson()["Sensor Class"]["TestSensorClass"]["Sources"];
ASSERT_EQ(2, sources.size());
ASSERT_TRUE(sources.find("temperature") != sources.end());
ASSERT_TRUE(sources.find("humidity-relative") != sources.end());
ASSERT_EQ("C", sources["temperature"].unit);
ASSERT_EQ(-17.0, sources["temperature"].min);
ASSERT_EQ(49.0, sources["temperature"].max);
ASSERT_EQ(1.0, sources["temperature"].accuracy);
}
TEST_F(iSensorType_unit, test_iTemperatureSensor)
{
/* Mock RHUSB class */
class RHUSB : public virtual upm::iTemperatureSensor
{
std::map<std::string, float> TemperatureForSources(std::vector<std::string> sources)
{
std::map<std::string, float> fake_temps;
if (std::find(sources.begin(), sources.end(), "temperature") != sources.end())
fake_temps["temperature"] = 25.5;
return fake_temps;
}
};
RHUSB ts;
ts.initFromJsonLibDesc("../../../src/rhusb/rhusb.json");
ASSERT_EQ(2, ts.Sources().size());
ASSERT_EQ(25.5, ts.TemperatureForSource("temperature"));
}

View File

@ -0,0 +1,104 @@
#include "gtest/gtest.h"
#include "iUpmObject.hpp"
#include "iServoActuator.hpp"
#include "external/json/json.hpp"
#include <vector>
#include <cstdlib>
/* Use the string literal operator from nlohmann */
using namespace nlohmann;
/* Mock ServoTest class */
class ES08A : public virtual upm::iServoActuator
{
public:
std::map<std::string, float> sinks;
ES08A()
{
sinks["axis0"] = 0.0;
sinks["axis1"] = 0.0;
/* Add a second command for testing */
AddCommand("axis1", "degrees");
}
void AngleForCommands(std::map<std::string, float> commands)
{
for(std::map<std::string, float>::const_iterator it = commands.begin(); it != commands.end(); ++it)
{
#ifndef NDEBUG
std::cout << "Received set angle command for: " << it->first << " value: " << it->second << std::endl;
#endif
std::map<std::string, float>::iterator sit = sinks.find(it->first);
if (sit == sinks.end())
throw std::invalid_argument("Servo axis: " + it->first + " not found");
sit->second = it->second;
}
}
};
/* Interfaces test fixture */
class iServoActuator_unit : public ::testing::Test
{
protected:
iServoActuator_unit() {}
virtual ~iServoActuator_unit() {}
virtual void SetUp()
{
/* Initialize from servo.json */
sref.initFromJsonLibDesc("../../../src/servo/servo.json");
}
virtual void TearDown() {}
ES08A sref;
};
TEST_F(iServoActuator_unit, test_iServoActuator_basic)
{
ASSERT_EQ(2, sref.Commands().size());
}
TEST_F(iServoActuator_unit, test_iServoActuator_serialize_command)
{
upm::ActuatorCommand<float> acmd;
acmd.command = "axis0";
acmd.unit = "degrees";
acmd.value = 30.0;
json jcmd = acmd;
ASSERT_EQ("{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0}", jcmd.dump());
}
TEST_F(iServoActuator_unit, test_iServoActuator_deserialize_command)
{
json jcmd = "{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0}"_json;
upm::ActuatorCommand<float> acmd = jcmd;
}
TEST_F(iServoActuator_unit, test_iServoActuator_run_command)
{
sref.AngleFromJson("{\"command\":\"axis0\",\"unit\":\"radians\",\"value\":3.14159}");
ASSERT_FLOAT_EQ(3.14159, sref.sinks["axis0"]);
}
TEST_F(iServoActuator_unit, test_iServoActuator_run_command_invalid_command)
{
ASSERT_THROW(sref.AngleFromJson("{\"command\":\"axis_doesn't_exist\",\"unit\":\"radians\",\"value\":3.14159}"),
std::invalid_argument);
}
TEST_F(iServoActuator_unit, test_iServoActuator_run_command_fail_deserialization)
{
ASSERT_THROW(sref.AngleFromJson("This is not }{ a valid JSON string"),
std::invalid_argument);
}
TEST_F(iServoActuator_unit, test_iServoActuator_run_commands)
{
sref.AngleFromJson("[{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0},{\"command\":\"axis1\",\"unit\":\"radians\",\"value\":3.1}]");
}

View File

@ -0,0 +1,55 @@
#include "gtest/gtest.h"
#include "iUpmObject.hpp"
#include "iSensorType.hpp"
class TestSensorClass : public virtual upm::iUpmObject
{
};
/* Interfaces test fixture */
class iUpmObject_unit : public ::testing::Test
{
protected:
/* One-time setup logic if needed */
iUpmObject_unit()
{
/* Load a specific JSON library descriptor file */
obj.initFromJsonLibDesc("./sensortype_example.json");
}
/* One-time tear-down logic if needed */
virtual ~iUpmObject_unit() {}
/* Per-test setup logic if needed */
virtual void SetUp() {}
/* Per-test tear-down logic if needed */
virtual void TearDown() {}
/* Instance of the test class */
TestSensorClass obj;
};
TEST_F(iUpmObject_unit, test_json_basic)
{
/* Basic checking */
ASSERT_EQ(obj.DerivedClassName(), "TestSensorClass");
ASSERT_EQ(obj.Description(), "This is a description");
ASSERT_EQ(obj.LibraryBaseName(), "core_tests");
ASSERT_EQ(obj.Name(), "TestSensorClass");
}
TEST_F(iUpmObject_unit, test_json_deserialize_basic)
{
/* Basic checking */
ASSERT_EQ(obj.Name(), "TestSensorClass");
ASSERT_EQ(obj.Description(), "This is a description");
}
/* Currently no need for a custom main (use gtest's)
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
*/

View File

@ -0,0 +1,45 @@
{
"Library": "core_tests",
"Description": "Unit test JSON example",
"Sensor Class": {
"TestSensorClass": {
"Name": "This is a name",
"Description": "This is a description",
"Aliases": ["Alias blibbity", "Alias blah"],
"Categories": ["humidity", "temperature"],
"Connections": ["uart"],
"Project Type": ["industrial", "commercial"],
"Manufacturers": ["Omega"],
"Sources" : {
"temperature": {
"unit": "C",
"min" : -17,
"max" : 49,
"accuracy" : 1
},
"humidity-relative": {
"unit": "%",
"min" : 2,
"max" : 98,
"accuracy" : 3
}
},
"Specifications": {
"Vsource": {
"unit": "V",
"min": 5.0,
"max": 5.0
},
"Operating Temperature": {
"unit": "°C",
"min": -40,
"max": 85
}
}
},
"Urls": {
"Product Pages": ["http://www.omega.com/pptst/RH-USB.html"],
"Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"]
}
}
}