#include #include #include // ----------------------------------------------------------------------------- // Tests // ----------------------------------------------------------------------------- #include #include #include "libs/TypeChecks.h" #include "tuya_types.h" #include "tuya_util.h" #include "tuya_transport.h" #include "tuya_protocol.h" #include "tuya_dataframe.h" using namespace Tuya; static bool datatype_same(const DataFrame& frame, const Type expect_type) { const auto type = dataType(frame); return expect_type == type; } void test_states() { States states(8); // Will not update anything without explicit push states.update(1, false); states.update(1, true); states.update(2, true); states.update(2, false); TEST_ASSERT_EQUAL_MESSAGE(8, states.capacity(), "Capacity has changed"); TEST_ASSERT_EQUAL_MESSAGE(0, states.size(), "Size should not change when updating non-existant id"); // Push something at specific ID states.pushOrUpdate(2, true); TEST_ASSERT_MESSAGE(states.changed(), "Should change after explicit push"); states.pushOrUpdate(2, false); TEST_ASSERT_MESSAGE(states.changed(), "Should change after explicit update"); TEST_ASSERT_EQUAL_MESSAGE(1, states.size(), "Size should not change when updating existing id"); states.pushOrUpdate(3, true); TEST_ASSERT_MESSAGE(states.changed(), "Should change after explicit push"); // Do not trigger "changed" state when value remains the same states.pushOrUpdate(2, false); TEST_ASSERT_MESSAGE(!states.changed(), "Should not change after not changing any values"); // Still shouldn't trigger "changed" without explicit push states.update(4, false); TEST_ASSERT_MESSAGE(!states.changed(), "Should not change after updating non-existant id"); TEST_ASSERT_EQUAL_MESSAGE(2, states.size(), "Size should remain the same after updating non-existant id"); } void test_static_dataframe_bool() { DataFrame frame(Command::SetDP, DataProtocol(0x02, false).serialize()); TEST_ASSERT_EQUAL_MESSAGE(0, frame.version, "Version should stay 0 unless explicitly set"); TEST_ASSERT_MESSAGE(frame.commandEquals(Command::SetDP), "commandEquals should return true with the same arg as in the constructor"); TEST_ASSERT_MESSAGE(datatype_same(frame, Type::BOOL), "DataProtocol should translate to Type::BOOL"); } void test_static_dataframe_int() { DataFrame frame(Command::ReportDP, DataProtocol(0x03, 255).serialize()); TEST_ASSERT_EQUAL_MESSAGE(0, frame.version, "Version should stay 0 unless explicitly set"); TEST_ASSERT_MESSAGE(frame.commandEquals(Command::ReportDP), "commandEquals should return true with the same arg as in the constructor"); TEST_ASSERT_EQUAL_UINT_MESSAGE(std::distance(frame.cbegin(), frame.cend()), frame.length, "Data is expected to be stored in a contigious memory and be equal in length to the ::length attribute"); TEST_ASSERT_EQUAL_MESSAGE(0, frame[5], "Only last byte should be set"); TEST_ASSERT_EQUAL_MESSAGE(255, frame[7], "Only last byte should be set"); } void test_static_dataframe_heartbeat() { DataFrame frame(Command::Heartbeat); TEST_ASSERT_EQUAL_MESSAGE(0, frame.length, "Frame with Command::Heartbeat should not have any data attached to it"); TEST_ASSERT_EQUAL_MESSAGE(0, std::distance(frame.cbegin(), frame.cend()), "Frame with Command::SetDP should not have any data attached to it"); //test_hexdump("static", static_frame.serialize()); } void test_dataframe_const() { const DataFrame frame(Command::SetDP); TEST_ASSERT_EQUAL_MESSAGE(0, frame.length, "Frame with Command::SetDP should not have any data attached to it"); TEST_ASSERT_EQUAL_MESSAGE(0, std::distance(frame.cbegin(), frame.cend()), "Frame with Command::SetDP should not have any data attached to it"); } void test_dataframe_copy() { DataFrame frame(Command::Heartbeat); frame.version = 0x7f; DataFrame moved_frame(std::move(frame)); TEST_ASSERT_EQUAL_MESSAGE(0x7f, moved_frame.version, "DataFrame should be movable object"); TEST_ASSERT_MESSAGE(!std::is_copy_constructible::value, "DataFrame should not be copyable"); } void test_dataframe_raw_data() { { const std::vector data = {0x55, 0xaa, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01}; DataFrame frame(data.cbegin()); TEST_ASSERT_MESSAGE(frame.commandEquals(Command::Heartbeat), "This message should be parsed as heartbeat"); TEST_ASSERT_EQUAL_MESSAGE(0, frame.version, "This message should have version == 0"); TEST_ASSERT_EQUAL_MESSAGE(1, frame.length, "Heartbeat message contains a single byte"); TEST_ASSERT_EQUAL_MESSAGE(1, frame[0], "Heartbeat message contains a single 0x01"); } { const std::vector data = {0x55, 0xaa, 0x00, 0x07, 0x00, 0x05, 0x01, 0x01, 0x00, 0x01, 0x01, 0x0f}; DataFrame frame(data.cbegin()); TEST_ASSERT_MESSAGE(frame.commandEquals(Command::ReportDP), "This message should be parsed as data protocol"); TEST_ASSERT_MESSAGE(datatype_same(frame, Type::BOOL), "This message should have boolean datatype attached to it"); TEST_ASSERT_EQUAL_MESSAGE(5, frame.length, "Boolean DP contains 5 bytes"); const DataProtocol dp(frame); TEST_ASSERT_EQUAL_MESSAGE(1, dp.id(), "This boolean DP id should be 1"); TEST_ASSERT_MESSAGE(dp.value(), "This boolean DP value should be true"); } //show_datatype(frame); //std::cout << "length=" << frame.length << std::endl; //test_hexdump("input", frame.serialize()); //std::cout << "[" << millis() << "] -------------------bad dp frame----------------" << std::endl; //DataFrame bad_dp_frame(Command::ReportDP, DataProtocol(0x03, 255).serialize()); //show_datatype(bad_dp_frame); //std::cout << "length=" << bad_dp_frame.length << std::endl; //test_hexdump("input", bad_dp_frame.serialize()); } class BufferedStream : public Stream { public: // Print interface size_t write(uint8_t c) { _buffer.push((int)c); return 1; } size_t write(const unsigned char* data, unsigned long size) { for (size_t n = 0; n < size; ++n) { _buffer.push(data[n]); } return size; } int availableForWrite() { return 1; } void flush() { while (!_buffer.empty()) { _buffer.pop(); } } // Stream interface int available() { return _buffer.size(); } int read() { if (!_buffer.size()) return -1; int c = _buffer.front(); _buffer.pop(); return c; } int peek() { if (!_buffer.size()) return -1; return _buffer.front(); } private: std::queue _buffer; }; void test_transport() { const std::vector data = {0x55, 0xaa, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01}; BufferedStream stream; stream.write(data.data(), data.size()); Transport transport(stream); TEST_ASSERT_MESSAGE(transport.available(), "Available data"); } int main(int argc, char** argv) { UNITY_BEGIN(); RUN_TEST(test_states); RUN_TEST(test_static_dataframe_bool); RUN_TEST(test_static_dataframe_int); RUN_TEST(test_static_dataframe_heartbeat); RUN_TEST(test_dataframe_const); RUN_TEST(test_dataframe_copy); RUN_TEST(test_dataframe_raw_data); RUN_TEST(test_transport); UNITY_END(); }