Alex2ESP/test/test_dispatch/test_main.cpp
David 6e15226ce0 Log: one line for whatever is dropped, a level the build lacks is reported, no false alarm for a 1.x handler
Audit of the paths that drop or refuse something. registerEvent() dropped an eleventh
handler and a second one for the same name without a word: the name now gets the new
handler, an eleventh name and a call without a name or a function print an error. A
device that cannot be announced printed two lines, one without its id; it prints one.
setLogLevel() above ALEX2ESP_LOG_MAX prints an error that names the build flag.
"the handler sent no answer" is an error for a handler of onDirective() only: a 1.x
handler may answer from a later loop(), its silence is a line at DEBUG.
getDevice() returning nullptr and printMemoryInfo() are documented; keywords.txt has
the 2.0 names and loses three that were removed.
basicLight: static RAM 30,520 B, flash 333,989 B (+600); ALEX2ESP_LOG_MAX=0 30,496 /
327,953, =3 30,520 / 334,477; five examples, log0 and log3 build with 0 warnings.
Host tests: 135 (dispatch 11 -> 16).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 21:10:19 +00:00

539 lines
21 KiB
C++

// 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); and of the log level (src/AlexaLog.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);
AlexaLog::setLevel(static_cast<AlexaLogLevel>(2));
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_handler_of_1x_that_answers_later_is_not_reported(void)
{
CapturedLog log;
AlexaLog::setOutput(&log);
AlexaLog::setLevel(static_cast<AlexaLogLevel>(1));
FakeTransport transport;
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
lamp.addCapability(AlexaInterfaceType::POWER_CONTROLLER);
lamp.registerEvent("Event", onEvent);
JsonDocument message;
directiveFor(message, "ESP-01", "Alexa.PowerController", "TurnOn");
lamp.handleDirective(message);
TEST_ASSERT_EQUAL(1, eventCalls);
TEST_ASSERT_EQUAL(0, transport.sent.size());
TEST_ASSERT_EQUAL_STRING("", log.text.c_str());
// The answer from loop(), with the token the sketch kept
TEST_ASSERT_TRUE(lamp.buildStatusMessage("token-of-the-directive", true).AddPowerControllerProp(PowerController::ON).send());
TEST_ASSERT_EQUAL(1, transport.sent.size());
}
void test_second_handler_for_an_event_replaces_the_first(void)
{
FakeTransport transport;
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
lamp.registerEvent("Event", onReportState);
lamp.registerEvent("Event", onEvent);
JsonDocument message;
lamp.triggerEvent("Event", message, AlexaInterfaceType::UNKNOWN);
TEST_ASSERT_EQUAL(1, eventCalls);
TEST_ASSERT_EQUAL(0, reportStateCalls);
}
void test_one_handler_more_than_a_device_keeps_is_refused_with_an_error(void)
{
CapturedLog log;
FakeTransport transport;
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
static const char *const NAMES[MAX_EVENTS] = {"Event", "ReportState", "DirectiveReceived", "A", "B",
"C", "D", "E", "F", "G"};
for (const char *name : NAMES)
{
lamp.registerEvent(name, onEvent);
}
AlexaLog::setOutput(&log);
lamp.registerEvent("Eleventh", onEvent);
lamp.registerEvent(nullptr, onEvent);
lamp.registerEvent("Event", nullptr);
assertLogged(log, "error: ESP-01: handler for Eleventh not registered: the device has 10 already (MAX_EVENTS)");
assertLogged(log, "error: ESP-01: handler not registered: registerEvent() takes the name of the event and a function");
JsonDocument message;
TEST_ASSERT_FALSE(lamp.triggerEvent("Eleventh", message, AlexaInterfaceType::UNKNOWN, false));
TEST_ASSERT_TRUE(lamp.triggerEvent("Event", message, AlexaInterfaceType::UNKNOWN, false));
TEST_ASSERT_TRUE(lamp.triggerEvent("G", message, AlexaInterfaceType::UNKNOWN, false));
TEST_ASSERT_EQUAL(2, eventCalls);
}
void test_level_above_the_ceiling_of_the_build_is_reported(void)
{
CapturedLog log;
AlexaLog::setOutput(&log);
AlexaLog::setLevel(static_cast<AlexaLogLevel>(ALEX2ESP_LOG_MAX));
TEST_ASSERT_EQUAL_STRING("", log.text.c_str());
AlexaLog::setLevel(static_cast<AlexaLogLevel>(ALEX2ESP_LOG_MAX + 1));
char expected[160];
snprintf(expected, sizeof(expected),
"error: log level %d asked for, the lines of this build end at level %d: build with -DALEX2ESP_LOG_MAX=%d",
ALEX2ESP_LOG_MAX + 1, ALEX2ESP_LOG_MAX, ALEX2ESP_LOG_MAX + 1);
assertLogged(log, expected);
}
void test_level_none_prints_nothing(void)
{
CapturedLog log;
AlexaLog::setOutput(&log);
AlexaLog::setLevel(static_cast<AlexaLogLevel>(0));
FakeTransport transport;
AlexaDevice lamp("Lamp", "root", "ESP-01", &transport);
JsonDocument message;
directiveFor(message, "ESP-01", "Alexa.PowerController", "TurnOn");
lamp.handleDirective(message);
// The answer is sent all the same
assertErrorResponse(transport.sent[0], "root/ESP-01/alexaResponce");
TEST_ASSERT_EQUAL_STRING("", log.text.c_str());
}
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_handler_of_1x_that_answers_later_is_not_reported);
RUN_TEST(test_second_handler_for_an_event_replaces_the_first);
RUN_TEST(test_one_handler_more_than_a_device_keeps_is_refused_with_an_error);
RUN_TEST(test_level_above_the_ceiling_of_the_build_is_reported);
RUN_TEST(test_level_none_prints_nothing);
RUN_TEST(test_handlers_of_1x_get_report_state_and_the_type_of_every_other_directive);
return UNITY_END();
}