444 lines
14 KiB
C++
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
|