AlexaDevice: capability array, linked list, a directive handler with the device in hand
onDirective(handler) registers void handler(AlexaDirective&): the directive comes with its device, the capability it is for, namespace, name, instance, correlationToken and payload, and response() and stateReport() build the answer, so one function serves several devices. registerEvent() is kept; the five examples compile unchanged and announce the same discovery objects. Devices are a linked list on the bridge and a device holds ALEX2ESP_MAX_CAPABILITIES (8) capability pointers in place of two std::deque; one capability more is refused with an error. A device without a handler, and a handler that sends nothing for a capability the device lacks, are answered with the ErrorResponse INVALID_DIRECTIVE instead of a timeout. A directive whose endpointId is not a device of the sketch is ignored at DEBUG. basicLight on a D1 mini: static RAM 30,672 -> 30,600 B, flash 332,541 -> 333,437 B, 0 warnings in the five examples; 88 host tests (11 new, test/test_dispatch). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
7afc4346e8
commit
d3e7ee7f2a
10 changed files with 767 additions and 67 deletions
438
test/test_dispatch/test_main.cpp
Normal file
438
test/test_dispatch/test_main.cpp
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
// Host tests of dispatch: which device and which capability a directive reaches, what the handler is given, what
|
||||
// a device holds, and what the device answers itself (src/AlexaDevice.cpp). The transport of the devices is a
|
||||
// fake that keeps what would have been published.
|
||||
// pio test -e native
|
||||
#include <unity.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "AlexaDevice.h"
|
||||
#include "AlexaLog.h"
|
||||
|
||||
class FakeTransport : public AlexaTransport
|
||||
{
|
||||
public:
|
||||
struct Message
|
||||
{
|
||||
std::string topic;
|
||||
std::string json;
|
||||
};
|
||||
std::vector<Message> sent;
|
||||
|
||||
AlexaSendResult publish(const char *topic, JsonDocument &doc) override
|
||||
{
|
||||
Message message;
|
||||
message.topic = topic;
|
||||
serializeJson(doc, message.json);
|
||||
sent.push_back(message);
|
||||
return AlexaSendResult::OK;
|
||||
}
|
||||
|
||||
void timestamp(char *buffer, size_t size) override { snprintf(buffer, size, "2026-09-28T13:05:09Z"); }
|
||||
};
|
||||
|
||||
class CapturedLog : public Print
|
||||
{
|
||||
public:
|
||||
std::string text;
|
||||
|
||||
size_t write(const uint8_t *buffer, size_t size) override
|
||||
{
|
||||
text.append(reinterpret_cast<const char *>(buffer), size);
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
static void assertLogged(const CapturedLog &log, const char *expected)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(log.text.c_str(), expected), log.text.c_str());
|
||||
}
|
||||
|
||||
// What the handler of the tests was given, copied: the texts of a directive end with the handler
|
||||
struct Seen
|
||||
{
|
||||
int calls;
|
||||
AlexaDevice *device;
|
||||
AlexaCapability *capability;
|
||||
AlexaInterfaceType type;
|
||||
std::string ns;
|
||||
std::string name;
|
||||
std::string instance;
|
||||
std::string correlationToken;
|
||||
int rangeValue;
|
||||
bool reportState;
|
||||
};
|
||||
|
||||
static Seen seen;
|
||||
static bool handlerAnswers;
|
||||
|
||||
static void onDirective(AlexaDirective &directive)
|
||||
{
|
||||
seen.calls++;
|
||||
seen.device = directive.device;
|
||||
seen.capability = directive.capability;
|
||||
seen.type = directive.type;
|
||||
seen.ns = directive.ns;
|
||||
seen.name = directive.name;
|
||||
seen.instance = directive.instance;
|
||||
seen.correlationToken = directive.correlationToken;
|
||||
seen.rangeValue = directive.payload["rangeValue"] | -1;
|
||||
seen.reportState = directive.isReportState();
|
||||
if (!handlerAnswers)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (directive.isReportState())
|
||||
{
|
||||
directive.stateReport().AddPowerControllerProp(PowerController::OFF).send();
|
||||
}
|
||||
else
|
||||
{
|
||||
directive.response().AddPowerControllerProp(directive.is("TurnOn") ? PowerController::ON : PowerController::OFF).send();
|
||||
}
|
||||
}
|
||||
|
||||
static int eventCalls;
|
||||
static int reportStateCalls;
|
||||
static AlexaInterfaceType eventType;
|
||||
|
||||
static void onEvent(const JsonDocument &, const AlexaInterfaceType &type)
|
||||
{
|
||||
eventCalls++;
|
||||
eventType = type;
|
||||
}
|
||||
|
||||
static void onReportState(const JsonDocument &, const AlexaInterfaceType &)
|
||||
{
|
||||
reportStateCalls++;
|
||||
}
|
||||
|
||||
// The directive as Alex2MQTT publishes it on <root>/<endpointId>/alexaDirective
|
||||
static void directiveFor(JsonDocument &message, const char *endpointId, const char *ns, const char *name,
|
||||
const char *instance = nullptr)
|
||||
{
|
||||
message.clear();
|
||||
message["header"]["namespace"] = ns;
|
||||
message["header"]["name"] = name;
|
||||
message["header"]["payloadVersion"] = "3";
|
||||
message["header"]["messageId"] = "5f8a426e-01e4-4cc9-8b79-65f8bd0fd8a4";
|
||||
message["header"]["correlationToken"] = "token-of-the-directive";
|
||||
if (instance != nullptr)
|
||||
{
|
||||
message["header"]["instance"] = instance;
|
||||
}
|
||||
message["endpoint"]["endpointId"] = endpointId;
|
||||
message["payload"].to<JsonObject>();
|
||||
}
|
||||
|
||||
static void assertErrorResponse(const FakeTransport::Message &message, const char *topic)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_STRING(topic, message.topic.c_str());
|
||||
JsonDocument answer;
|
||||
TEST_ASSERT_TRUE(deserializeJson(answer, message.json) == DeserializationError::Ok);
|
||||
TEST_ASSERT_EQUAL_STRING("Alexa", answer["event"]["header"]["namespace"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("ErrorResponse", answer["event"]["header"]["name"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("token-of-the-directive", answer["event"]["header"]["correlationToken"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("INVALID_DIRECTIVE", answer["event"]["payload"]["type"] | "");
|
||||
TEST_ASSERT_TRUE(strlen(answer["event"]["payload"]["message"] | "") > 0);
|
||||
TEST_ASSERT_TRUE(answer["context"].isNull()); // alexa-errorresponse.html: an ErrorResponse has no context
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
AlexaLog::setOutput(nullptr);
|
||||
seen = Seen();
|
||||
handlerAnswers = true;
|
||||
eventCalls = 0;
|
||||
reportStateCalls = 0;
|
||||
eventType = AlexaInterfaceType::UNKNOWN;
|
||||
}
|
||||
|
||||
void tearDown(void) {}
|
||||
|
||||
void test_devices_are_found_by_their_endpoint_id_in_the_order_they_were_created(void)
|
||||
{
|
||||
AlexaDeviceList devices;
|
||||
TEST_ASSERT_NULL(devices.first());
|
||||
AlexaDevice *lamp = devices.add("Lamp", "root", "ESP-01", nullptr);
|
||||
AlexaDevice *fan = devices.add("Fan", "root", "ESP-02", nullptr);
|
||||
AlexaDevice *blind = devices.add("Blind", "root", "ESP-03", nullptr);
|
||||
|
||||
TEST_ASSERT_EQUAL(3, devices.size());
|
||||
TEST_ASSERT_EQUAL_PTR(lamp, devices.first());
|
||||
TEST_ASSERT_EQUAL_PTR(fan, lamp->nextDevice());
|
||||
TEST_ASSERT_EQUAL_PTR(blind, fan->nextDevice());
|
||||
TEST_ASSERT_NULL(blind->nextDevice());
|
||||
TEST_ASSERT_EQUAL_PTR(fan, devices.find("ESP-02", 6));
|
||||
// The id is a part of a topic: "ESP-02/alexaDirective"
|
||||
TEST_ASSERT_EQUAL_PTR(fan, devices.find("ESP-02/alexaDirective", 6));
|
||||
// An endpoint of another board
|
||||
TEST_ASSERT_NULL(devices.find("ESP-04", 6));
|
||||
TEST_ASSERT_NULL(devices.find("ESP-0", 5));
|
||||
}
|
||||
|
||||
void test_one_handler_serves_two_devices_and_is_told_which(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDeviceList devices;
|
||||
AlexaDevice *lamp = devices.add("Lamp", "root", "ESP-01", &transport);
|
||||
AlexaDevice *fan = devices.add("Fan", "root", "ESP-02", &transport);
|
||||
lamp->addCapability(AlexaInterfaces::PowerController);
|
||||
AlexaCapability *fanPower = fan->addCapability(AlexaInterfaces::PowerController);
|
||||
lamp->onDirective(onDirective);
|
||||
fan->onDirective(onDirective);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-02", "Alexa.PowerController", "TurnOn");
|
||||
devices.find("ESP-02", 6)->handleDirective(message);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, seen.calls);
|
||||
TEST_ASSERT_EQUAL_PTR(fan, seen.device);
|
||||
TEST_ASSERT_EQUAL_PTR(fanPower, seen.capability);
|
||||
TEST_ASSERT_TRUE(AlexaInterfaceType::POWER_CONTROLLER == seen.type);
|
||||
TEST_ASSERT_EQUAL_STRING("Alexa.PowerController", seen.ns.c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("TurnOn", seen.name.c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("", seen.instance.c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("token-of-the-directive", seen.correlationToken.c_str());
|
||||
TEST_ASSERT_FALSE(seen.reportState);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, transport.sent.size());
|
||||
TEST_ASSERT_EQUAL_STRING("root/ESP-02/alexaResponce", transport.sent[0].topic.c_str());
|
||||
JsonDocument answer;
|
||||
TEST_ASSERT_TRUE(deserializeJson(answer, transport.sent[0].json) == DeserializationError::Ok);
|
||||
TEST_ASSERT_EQUAL_STRING("Response", answer["event"]["header"]["name"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("token-of-the-directive", answer["event"]["header"]["correlationToken"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("ESP-02", answer["event"]["endpoint"]["endpointId"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("ON", answer["context"]["properties"][0]["value"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("2026-09-28T13:05:09Z", answer["context"]["properties"][0]["timeOfSample"] | "");
|
||||
}
|
||||
|
||||
void test_directive_with_an_instance_reaches_the_capability_with_that_instance(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDevice blind("Blind", "root", "ESP-01", &transport);
|
||||
AlexaCapability *lift = blind.addCapability(AlexaInterfaces::RangeController, "Blind.Lift");
|
||||
AlexaCapability *tilt = blind.addCapability(AlexaInterfaces::RangeController, "Blind.Tilt");
|
||||
blind.onDirective(onDirective);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.RangeController", "SetRangeValue", "Blind.Tilt");
|
||||
message["payload"]["rangeValue"] = 40;
|
||||
blind.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(tilt, seen.capability);
|
||||
TEST_ASSERT_TRUE(AlexaInterfaceType::RANGE_CONTROLLER == seen.type);
|
||||
TEST_ASSERT_EQUAL_STRING("Blind.Tilt", seen.instance.c_str());
|
||||
TEST_ASSERT_EQUAL(40, seen.rangeValue);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(lift, blind.findCapability("Alexa.RangeController", "Blind.Lift"));
|
||||
TEST_ASSERT_NULL(blind.findCapability("Alexa.RangeController", "Blind.Slat"));
|
||||
TEST_ASSERT_NULL(blind.findCapability("Alexa.RangeController", ""));
|
||||
TEST_ASSERT_NULL(blind.findCapability("Alexa.ModeController", "Blind.Lift"));
|
||||
}
|
||||
|
||||
void test_report_state_is_handed_over_without_a_capability_and_answered_with_a_state_report(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
|
||||
lamp.addCapability(AlexaInterfaces::PowerController);
|
||||
lamp.onDirective(onDirective);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa", "ReportState");
|
||||
lamp.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_TRUE(seen.reportState);
|
||||
TEST_ASSERT_NULL(seen.capability);
|
||||
TEST_ASSERT_EQUAL(1, transport.sent.size());
|
||||
JsonDocument answer;
|
||||
TEST_ASSERT_TRUE(deserializeJson(answer, transport.sent[0].json) == DeserializationError::Ok);
|
||||
TEST_ASSERT_EQUAL_STRING("StateReport", answer["event"]["header"]["name"] | "");
|
||||
TEST_ASSERT_EQUAL_STRING("OFF", answer["context"]["properties"][0]["value"] | "");
|
||||
}
|
||||
|
||||
void test_one_capability_more_than_a_device_holds_is_refused_with_an_error(void)
|
||||
{
|
||||
CapturedLog log;
|
||||
AlexaDevice device("Panel", "root", "ESP-01");
|
||||
AlexaCapability *first = nullptr;
|
||||
for (int i = 0; i < ALEX2ESP_MAX_CAPABILITIES; i++)
|
||||
{
|
||||
char instance[16];
|
||||
snprintf(instance, sizeof(instance), "Panel.%d", i);
|
||||
AlexaCapability *added = device.addCapability(AlexaInterfaces::ToggleController, instance);
|
||||
TEST_ASSERT_NOT_NULL(added);
|
||||
added->addFriendlyName("Switch", "en-US");
|
||||
if (i == 0)
|
||||
{
|
||||
first = added;
|
||||
}
|
||||
}
|
||||
std::string full;
|
||||
serializeJson(device.getDeviceJSON(), full);
|
||||
|
||||
AlexaLog::setOutput(&log);
|
||||
TEST_ASSERT_NULL(device.addCapability(AlexaInterfaces::PowerController));
|
||||
TEST_ASSERT_NULL(device.addCapability(AlexaInterfaceType::BRIGHTNESS_CONTROLLER));
|
||||
|
||||
char expected[160];
|
||||
snprintf(expected, sizeof(expected),
|
||||
"error: ESP-01: capability Alexa.PowerController not added: the device has %d already "
|
||||
"(ALEX2ESP_MAX_CAPABILITIES)",
|
||||
ALEX2ESP_MAX_CAPABILITIES);
|
||||
assertLogged(log, expected);
|
||||
assertLogged(log, "error: ESP-01: capability Alexa.BrightnessController not added");
|
||||
|
||||
// What it has is still found and announced
|
||||
TEST_ASSERT_EQUAL_PTR(first, device.addCapability(AlexaInterfaces::ToggleController, "Panel.0"));
|
||||
TEST_ASSERT_NULL(device.findCapability("Alexa.PowerController", ""));
|
||||
std::string announced;
|
||||
serializeJson(device.getDeviceJSON(), announced);
|
||||
TEST_ASSERT_EQUAL_STRING(full.c_str(), announced.c_str());
|
||||
}
|
||||
|
||||
void test_directive_for_an_interface_the_device_lacks_is_answered_with_invalid_directive(void)
|
||||
{
|
||||
CapturedLog log;
|
||||
AlexaLog::setOutput(&log);
|
||||
FakeTransport transport;
|
||||
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
|
||||
lamp.addCapability(AlexaInterfaces::PowerController);
|
||||
lamp.onDirective(onDirective);
|
||||
handlerAnswers = false; // as a handler that knows its own interfaces and leaves the others alone
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.LockController", "Lock");
|
||||
lamp.handleDirective(message);
|
||||
|
||||
// The handler is asked first: it sees that the device has no such capability
|
||||
TEST_ASSERT_EQUAL(1, seen.calls);
|
||||
TEST_ASSERT_NULL(seen.capability);
|
||||
TEST_ASSERT_TRUE(AlexaInterfaceType::UNKNOWN == seen.type);
|
||||
TEST_ASSERT_EQUAL(1, transport.sent.size());
|
||||
assertErrorResponse(transport.sent[0], "root/ESP-01/alexaResponce");
|
||||
assertLogged(log, "error: ESP-01: Alexa.LockController.Lock refused as INVALID_DIRECTIVE: "
|
||||
"the device has no such capability");
|
||||
}
|
||||
|
||||
void test_instance_the_device_lacks_is_answered_with_invalid_directive(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDevice blind("Blind", "root", "ESP-01", &transport);
|
||||
blind.addCapability(AlexaInterfaces::RangeController, "Blind.Lift");
|
||||
blind.onDirective(onDirective);
|
||||
handlerAnswers = false;
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.RangeController", "SetRangeValue", "Blind.Tilt");
|
||||
blind.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_NULL(seen.capability);
|
||||
TEST_ASSERT_EQUAL(1, transport.sent.size());
|
||||
assertErrorResponse(transport.sent[0], "root/ESP-01/alexaResponce");
|
||||
}
|
||||
|
||||
void test_answer_of_the_handler_to_an_interface_the_device_lacks_is_the_only_answer(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
|
||||
lamp.addCapability(AlexaInterfaces::PowerController);
|
||||
lamp.onDirective(onDirective);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.LockController", "Lock");
|
||||
lamp.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, transport.sent.size());
|
||||
JsonDocument answer;
|
||||
TEST_ASSERT_TRUE(deserializeJson(answer, transport.sent[0].json) == DeserializationError::Ok);
|
||||
TEST_ASSERT_EQUAL_STRING("Response", answer["event"]["header"]["name"] | "");
|
||||
}
|
||||
|
||||
void test_device_without_a_handler_answers_with_invalid_directive(void)
|
||||
{
|
||||
CapturedLog log;
|
||||
AlexaLog::setOutput(&log);
|
||||
FakeTransport transport;
|
||||
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
|
||||
lamp.addCapability(AlexaInterfaces::PowerController);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.PowerController", "TurnOn");
|
||||
lamp.handleDirective(message);
|
||||
directiveFor(message, "ESP-01", "Alexa", "ReportState");
|
||||
lamp.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_EQUAL(2, transport.sent.size());
|
||||
assertErrorResponse(transport.sent[0], "root/ESP-01/alexaResponce");
|
||||
assertErrorResponse(transport.sent[1], "root/ESP-01/alexaResponce");
|
||||
assertLogged(log, "error: ESP-01: Alexa.PowerController.TurnOn refused as INVALID_DIRECTIVE: "
|
||||
"the device has no handler, give it one with onDirective()");
|
||||
}
|
||||
|
||||
void test_handler_that_sends_nothing_for_a_capability_of_the_device_is_reported(void)
|
||||
{
|
||||
CapturedLog log;
|
||||
AlexaLog::setOutput(&log);
|
||||
FakeTransport transport;
|
||||
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
|
||||
lamp.addCapability(AlexaInterfaces::PowerController);
|
||||
lamp.onDirective(onDirective);
|
||||
handlerAnswers = false;
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.PowerController", "TurnOn");
|
||||
lamp.handleDirective(message);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, seen.calls);
|
||||
TEST_ASSERT_EQUAL(0, transport.sent.size());
|
||||
assertLogged(log, "error: ESP-01: the handler sent no answer to Alexa.PowerController.TurnOn");
|
||||
}
|
||||
|
||||
void test_handlers_of_1x_get_report_state_and_the_type_of_every_other_directive(void)
|
||||
{
|
||||
FakeTransport transport;
|
||||
AlexaDevice blind("Blind", "root", "ESP-01", &transport);
|
||||
blind.addCapability(AlexaInterfaceType::POWER_CONTROLLER);
|
||||
blind.addCapability(AlexaInterfaceType::TOGGLE_CONTROLLER)->setInstance("ESP-01.Toggle");
|
||||
blind.registerEvent("ReportState", onReportState);
|
||||
blind.registerEvent("Event", onEvent);
|
||||
|
||||
JsonDocument message;
|
||||
directiveFor(message, "ESP-01", "Alexa.ToggleController", "TurnOn", "ESP-01.Toggle");
|
||||
blind.handleDirective(message);
|
||||
TEST_ASSERT_EQUAL(1, eventCalls);
|
||||
TEST_ASSERT_EQUAL(0, reportStateCalls);
|
||||
TEST_ASSERT_TRUE(AlexaInterfaceType::TOGGLE_CONTROLLER == eventType);
|
||||
|
||||
directiveFor(message, "ESP-01", "Alexa", "ReportState");
|
||||
blind.handleDirective(message);
|
||||
TEST_ASSERT_EQUAL(1, eventCalls);
|
||||
TEST_ASSERT_EQUAL(1, reportStateCalls);
|
||||
|
||||
// With a handler of 2.0 the device calls that one
|
||||
blind.onDirective(onDirective);
|
||||
directiveFor(message, "ESP-01", "Alexa.PowerController", "TurnOff");
|
||||
blind.handleDirective(message);
|
||||
TEST_ASSERT_EQUAL(1, eventCalls);
|
||||
TEST_ASSERT_EQUAL(1, seen.calls);
|
||||
}
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_devices_are_found_by_their_endpoint_id_in_the_order_they_were_created);
|
||||
RUN_TEST(test_one_handler_serves_two_devices_and_is_told_which);
|
||||
RUN_TEST(test_directive_with_an_instance_reaches_the_capability_with_that_instance);
|
||||
RUN_TEST(test_report_state_is_handed_over_without_a_capability_and_answered_with_a_state_report);
|
||||
RUN_TEST(test_one_capability_more_than_a_device_holds_is_refused_with_an_error);
|
||||
RUN_TEST(test_directive_for_an_interface_the_device_lacks_is_answered_with_invalid_directive);
|
||||
RUN_TEST(test_instance_the_device_lacks_is_answered_with_invalid_directive);
|
||||
RUN_TEST(test_answer_of_the_handler_to_an_interface_the_device_lacks_is_the_only_answer);
|
||||
RUN_TEST(test_device_without_a_handler_answers_with_invalid_directive);
|
||||
RUN_TEST(test_handler_that_sends_nothing_for_a_capability_of_the_device_is_reported);
|
||||
RUN_TEST(test_handlers_of_1x_get_report_state_and_the_type_of_every_other_directive);
|
||||
return UNITY_END();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue