avs-device-sdk/AVSCommon/AVS/test/CapabilitySemanticsTest.cpp

444 lines
14 KiB
C++

/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file 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.
*/
#include <AVSCommon/AVS/CapabilitySemantics/CapabilitySemantics.h>
#include <gtest/gtest.h>
#include <rapidjson/document.h>
namespace alexaClientSDK {
namespace avsCommon {
namespace avs {
namespace test {
using namespace ::testing;
using namespace avsCommon::avs::capabilitySemantics;
/// Accepted action IDs.
/// @{
static std::string ACTION_OPEN = "Alexa.Actions.Open";
static std::string ACTION_CLOSE = "Alexa.Actions.Close";
static std::string ACTION_RAISE = "Alexa.Actions.Raise";
static std::string ACTION_LOWER = "Alexa.Actions.Lower";
/// @}
/// Accepted state IDs.
/// @{
static std::string STATE_OPEN = "Alexa.States.Open";
static std::string STATE_CLOSED = "Alexa.States.Closed";
/// @}
/// Sample directive names.
/// @{
static std::string DIRECTIVE_TURNOFF = "TurnOff";
static std::string DIRECTIVE_SETMODE = "SetMode";
static std::string DIRECTIVE_SETRANGE = "SetRangeValue";
static std::string DIRECTIVE_ADJUSTRANGE = "AdjustRangeValue";
/// @}
// clang-format off
/**
* Sample 'semantics' object with multiple ActionsToDirectiveMappings with multiple actions.
*/
static std::string JSON_SEMANTICS_MULTIPLE_ACTIONS = R"({
"actionMappings": [
{
"@type": "ActionsToDirective",
"actions": ["Alexa.Actions.Close", "Alexa.Actions.Lower"],
"directive": {
"name": "SetMode",
"payload": {
"mode": "Position.Down"
}
}
},
{
"@type": "ActionsToDirective",
"actions": ["Alexa.Actions.Open", "Alexa.Actions.Raise"],
"directive": {
"name": "SetMode",
"payload": {
"mode": "Position.Up"
}
}
}
]
})";
/**
* Sample 'semantics' object with 'actionMappings' and 'stateMappings'.
*/
static std::string JSON_SEMANTICS_COMPLETE = R"({
"actionMappings": [
{
"@type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Close"
],
"directive": {
"name": "SetRangeValue",
"payload": {
"rangeValue": 0
}
}
},
{
"@type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Open"
],
"directive": {
"name": "SetRangeValue",
"payload": {
"rangeValue": 100
}
}
},
{
"@type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Lower"
],
"directive": {
"name": "AdjustRangeValue",
"payload": {
"rangeValueDelta": -10
}
}
},
{
"@type": "ActionsToDirective",
"actions": [
"Alexa.Actions.Raise"
],
"directive": {
"name": "AdjustRangeValue",
"payload": {
"rangeValueDelta": 10
}
}
}
],
"stateMappings": [
{
"@type": "StatesToValue",
"states": [
"Alexa.States.Closed"
],
"value": 0
},
{
"@type": "StatesToRange",
"states": [
"Alexa.States.Open"
],
"range": {
"minimumValue": 1,
"maximumValue": 100
}
}
]
})";
/// Empty JSON object.
static std::string JSON_EMPTY_OBJECT = "{}";
// clang-format on
/**
* Expects the provided JSON strings to be equal.
*/
void validateJson(const std::string& providedJson, const std::string& expectedJson) {
rapidjson::Document providedStateParsed;
providedStateParsed.Parse(providedJson);
rapidjson::Document expectedStateParsed;
expectedStateParsed.Parse(expectedJson);
EXPECT_EQ(providedStateParsed, expectedStateParsed);
}
/**
* The test harness for @c CapabilitySemantics.
*/
class CapabilitySemanticsTest : public Test {};
/**
* Test that ActionsToDirectiveMapping::addAction() checks for an empty action.
*/
TEST_F(CapabilitySemanticsTest, test_actions_emptyAction) {
ActionsToDirectiveMapping invalidMapping;
ASSERT_FALSE(invalidMapping.addAction(""));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that ActionsToDirectiveMapping::setDirective() checks for an empty name.
*/
TEST_F(CapabilitySemanticsTest, test_actions_emptyDirectiveName) {
ActionsToDirectiveMapping invalidMapping;
ASSERT_FALSE(invalidMapping.setDirective("", JSON_EMPTY_OBJECT));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that ActionsToDirectiveMapping::addAction() skips duplicate actions.
*/
TEST_F(CapabilitySemanticsTest, test_actions_duplicateAction) {
ActionsToDirectiveMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setDirective(DIRECTIVE_TURNOFF, JSON_EMPTY_OBJECT));
ASSERT_TRUE(invalidMapping.addAction(ACTION_CLOSE));
ASSERT_TRUE(invalidMapping.isValid());
ASSERT_FALSE(invalidMapping.addAction(ACTION_CLOSE));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that ActionsToDirectiveMapping without actions is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_actions_noActions) {
ActionsToDirectiveMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setDirective(DIRECTIVE_TURNOFF, JSON_EMPTY_OBJECT));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that ActionsToDirectiveMapping without a directive is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_actions_noDirective) {
ActionsToDirectiveMapping invalidMapping;
ASSERT_TRUE(invalidMapping.addAction(ACTION_CLOSE));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToValueMapping::addState() checks for an empty state.
*/
TEST_F(CapabilitySemanticsTest, test_statesValue_emptyState) {
StatesToValueMapping invalidMapping;
ASSERT_FALSE(invalidMapping.addState(""));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToValueMapping::addState() skips duplicate states.
*/
TEST_F(CapabilitySemanticsTest, test_statesValue_duplicateState) {
StatesToValueMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setValue("Position.Down"));
ASSERT_TRUE(invalidMapping.addState(STATE_CLOSED));
ASSERT_TRUE(invalidMapping.isValid());
ASSERT_FALSE(invalidMapping.addState(STATE_CLOSED));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToValueMapping without states is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_statesValue_noStates) {
StatesToValueMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setValue(0));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToValueMapping without a value is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_statesValue_noValue) {
StatesToValueMapping invalidMapping;
ASSERT_TRUE(invalidMapping.addState(STATE_CLOSED));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToRangeMapping::addState() checks for an empty state.
*/
TEST_F(CapabilitySemanticsTest, test_statesRange_emptyState) {
StatesToRangeMapping invalidMapping;
ASSERT_FALSE(invalidMapping.addState(""));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToRangeMapping::addState() skips duplicate states.
*/
TEST_F(CapabilitySemanticsTest, test_statesRange_duplicateState) {
StatesToRangeMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setRange(0, 50));
ASSERT_TRUE(invalidMapping.addState(STATE_OPEN));
ASSERT_TRUE(invalidMapping.isValid());
ASSERT_FALSE(invalidMapping.addState(STATE_OPEN));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToRangeMapping without states is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_statesRange_noStates) {
StatesToRangeMapping invalidMapping;
ASSERT_TRUE(invalidMapping.setRange(0, 50));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToRangeMapping without a range is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_statesRange_noRange) {
StatesToRangeMapping invalidMapping;
ASSERT_TRUE(invalidMapping.addState(STATE_CLOSED));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that StatesToRangeMapping with min > max is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_statesRange_invertedRange) {
StatesToRangeMapping invalidMapping;
ASSERT_TRUE(invalidMapping.addState(STATE_OPEN));
ASSERT_FALSE(invalidMapping.setRange(100, 1));
ASSERT_FALSE(invalidMapping.isValid());
ASSERT_EQ(invalidMapping.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that CapabilitySemantics without mappings is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_semantics_noMappings) {
CapabilitySemantics invalidSemantics;
ASSERT_FALSE(invalidSemantics.isValid());
validateJson(invalidSemantics.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that CapabilitySemantics with an invalid ActionsToDirectiveMapping is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_semantics_invalidActionsDirectiveMapping) {
ActionsToDirectiveMapping invalidMapping;
CapabilitySemantics invalidSemantics;
ASSERT_FALSE(invalidSemantics.addActionsToDirectiveMapping(invalidMapping));
ASSERT_FALSE(invalidSemantics.isValid());
validateJson(invalidSemantics.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that CapabilitySemantics with an invalid StatesToValueMapping is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_semantics_invalidStatesValueMapping) {
StatesToValueMapping invalidMapping;
CapabilitySemantics invalidSemantics;
ASSERT_FALSE(invalidSemantics.addStatesToValueMapping(invalidMapping));
ASSERT_FALSE(invalidSemantics.isValid());
validateJson(invalidSemantics.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test that CapabilitySemantics with an invalid StatesToRangeMapping is invalid.
*/
TEST_F(CapabilitySemanticsTest, test_semantics_invalidStatesRangeMapping) {
StatesToRangeMapping invalidMapping;
CapabilitySemantics invalidSemantics;
ASSERT_FALSE(invalidSemantics.addStatesToRangeMapping(invalidMapping));
ASSERT_FALSE(invalidSemantics.isValid());
validateJson(invalidSemantics.toJson(), JSON_EMPTY_OBJECT);
}
/**
* Test the JSON result of an ActionsToDirectiveMapping with multiple actions.
*/
TEST_F(CapabilitySemanticsTest, test_validateJson_semanticsMultipleActionMappings) {
ActionsToDirectiveMapping setModeDownMapping;
ASSERT_TRUE(setModeDownMapping.addAction(ACTION_CLOSE));
ASSERT_TRUE(setModeDownMapping.addAction(ACTION_LOWER));
ASSERT_TRUE(setModeDownMapping.setDirective(DIRECTIVE_SETMODE, "{\"mode\": \"Position.Down\"}"));
ASSERT_TRUE(setModeDownMapping.isValid());
ActionsToDirectiveMapping setModeUpMapping;
ASSERT_TRUE(setModeUpMapping.addAction(ACTION_OPEN));
ASSERT_TRUE(setModeUpMapping.addAction(ACTION_RAISE));
ASSERT_TRUE(setModeUpMapping.setDirective(DIRECTIVE_SETMODE, "{\"mode\": \"Position.Up\"}"));
ASSERT_TRUE(setModeUpMapping.isValid());
CapabilitySemantics semantics;
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(setModeDownMapping));
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(setModeUpMapping));
ASSERT_TRUE(semantics.isValid());
validateJson(semantics.toJson(), JSON_SEMANTICS_MULTIPLE_ACTIONS);
}
/**
* Test the JSON result of a CapabilitySemantics with all mapping types.
*/
TEST_F(CapabilitySemanticsTest, test_validateJson_semanticsComplete) {
ActionsToDirectiveMapping closeMapping;
ASSERT_TRUE(closeMapping.addAction(ACTION_CLOSE));
ASSERT_TRUE(closeMapping.setDirective(DIRECTIVE_SETRANGE, "{\"rangeValue\" : 0}"));
ASSERT_TRUE(closeMapping.isValid());
ActionsToDirectiveMapping openMapping;
ASSERT_TRUE(openMapping.addAction(ACTION_OPEN));
ASSERT_TRUE(openMapping.setDirective(DIRECTIVE_SETRANGE, "{\"rangeValue\" : 100}"));
ASSERT_TRUE(openMapping.isValid());
ActionsToDirectiveMapping lowerMapping;
ASSERT_TRUE(lowerMapping.addAction(ACTION_LOWER));
ASSERT_TRUE(lowerMapping.setDirective(DIRECTIVE_ADJUSTRANGE, "{\"rangeValueDelta\" : -10}"));
ASSERT_TRUE(lowerMapping.isValid());
ActionsToDirectiveMapping raiseMapping;
ASSERT_TRUE(raiseMapping.addAction(ACTION_RAISE));
ASSERT_TRUE(raiseMapping.setDirective(DIRECTIVE_ADJUSTRANGE, "{\"rangeValueDelta\" : 10}"));
ASSERT_TRUE(raiseMapping.isValid());
StatesToValueMapping closedMapping;
ASSERT_TRUE(closedMapping.addState(STATE_CLOSED));
ASSERT_TRUE(closedMapping.setValue(0));
ASSERT_TRUE(closedMapping.isValid());
StatesToRangeMapping openedMapping;
ASSERT_TRUE(openedMapping.addState(STATE_OPEN));
ASSERT_TRUE(openedMapping.setRange(1, 100));
ASSERT_TRUE(openedMapping.isValid());
CapabilitySemantics semantics;
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(closeMapping));
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(openMapping));
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(lowerMapping));
ASSERT_TRUE(semantics.addActionsToDirectiveMapping(raiseMapping));
ASSERT_TRUE(semantics.addStatesToValueMapping(closedMapping));
ASSERT_TRUE(semantics.addStatesToRangeMapping(openedMapping));
ASSERT_TRUE(semantics.isValid());
validateJson(semantics.toJson(), JSON_SEMANTICS_COMPLETE);
}
} // namespace test
} // namespace avs
} // namespace avsCommon
} // namespace alexaClientSDK