Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
7.9 KiB

  1. #include <Arduino.h>
  2. #include <Stream.h>
  3. #include <unity.h>
  4. // -----------------------------------------------------------------------------
  5. // Tests
  6. // -----------------------------------------------------------------------------
  7. #include <type_traits>
  8. #include <queue>
  9. #include "libs/TypeChecks.h"
  10. #include "tuya_types.h"
  11. #include "tuya_util.h"
  12. #include "tuya_transport.h"
  13. #include "tuya_protocol.h"
  14. #include "tuya_dataframe.h"
  15. using namespace Tuya;
  16. static bool datatype_same(const DataFrame& frame, const Type expect_type) {
  17. const auto type = dataType(frame);
  18. return expect_type == type;
  19. }
  20. void test_states() {
  21. States<bool> states(8);
  22. // Will not update anything without explicit push
  23. states.update(1, false);
  24. states.update(1, true);
  25. states.update(2, true);
  26. states.update(2, false);
  27. TEST_ASSERT_EQUAL_MESSAGE(8, states.capacity(),
  28. "Capacity has changed");
  29. TEST_ASSERT_EQUAL_MESSAGE(0, states.size(),
  30. "Size should not change when updating non-existant id");
  31. // Push something at specific ID
  32. states.pushOrUpdate(2, true);
  33. TEST_ASSERT_MESSAGE(states.changed(),
  34. "Should change after explicit push");
  35. states.pushOrUpdate(2, false);
  36. TEST_ASSERT_MESSAGE(states.changed(),
  37. "Should change after explicit update");
  38. TEST_ASSERT_EQUAL_MESSAGE(1, states.size(),
  39. "Size should not change when updating existing id");
  40. states.pushOrUpdate(3, true);
  41. TEST_ASSERT_MESSAGE(states.changed(),
  42. "Should change after explicit push");
  43. // Do not trigger "changed" state when value remains the same
  44. states.pushOrUpdate(2, false);
  45. TEST_ASSERT_MESSAGE(!states.changed(),
  46. "Should not change after not changing any values");
  47. // Still shouldn't trigger "changed" without explicit push
  48. states.update(4, false);
  49. TEST_ASSERT_MESSAGE(!states.changed(),
  50. "Should not change after updating non-existant id");
  51. TEST_ASSERT_EQUAL_MESSAGE(2, states.size(),
  52. "Size should remain the same after updating non-existant id");
  53. }
  54. void test_static_dataframe_bool() {
  55. DataFrame frame(Command::SetDP, DataProtocol<bool>(0x02, false).serialize());
  56. TEST_ASSERT_EQUAL_MESSAGE(0, frame.version,
  57. "Version should stay 0 unless explicitly set");
  58. TEST_ASSERT_MESSAGE(frame.commandEquals(Command::SetDP),
  59. "commandEquals should return true with the same arg as in the constructor");
  60. TEST_ASSERT_MESSAGE(datatype_same(frame, Type::BOOL),
  61. "DataProtocol<bool> should translate to Type::BOOL");
  62. }
  63. void test_static_dataframe_int() {
  64. DataFrame frame(Command::ReportDP, DataProtocol<uint32_t>(0x03, 255).serialize());
  65. TEST_ASSERT_EQUAL_MESSAGE(0, frame.version,
  66. "Version should stay 0 unless explicitly set");
  67. TEST_ASSERT_MESSAGE(frame.commandEquals(Command::ReportDP),
  68. "commandEquals should return true with the same arg as in the constructor");
  69. TEST_ASSERT_EQUAL_UINT_MESSAGE(std::distance(frame.cbegin(), frame.cend()), frame.length,
  70. "Data is expected to be stored in a contigious memory and be equal in length to the ::length attribute");
  71. TEST_ASSERT_EQUAL_MESSAGE(0, frame[5],
  72. "Only last byte should be set");
  73. TEST_ASSERT_EQUAL_MESSAGE(255, frame[7],
  74. "Only last byte should be set");
  75. }
  76. void test_static_dataframe_heartbeat() {
  77. DataFrame frame(Command::Heartbeat);
  78. TEST_ASSERT_EQUAL_MESSAGE(0, frame.length,
  79. "Frame with Command::Heartbeat should not have any data attached to it");
  80. TEST_ASSERT_EQUAL_MESSAGE(0, std::distance(frame.cbegin(), frame.cend()),
  81. "Frame with Command::SetDP should not have any data attached to it");
  82. //test_hexdump("static", static_frame.serialize());
  83. }
  84. void test_dataframe_const() {
  85. const DataFrame frame(Command::SetDP);
  86. TEST_ASSERT_EQUAL_MESSAGE(0, frame.length,
  87. "Frame with Command::SetDP should not have any data attached to it");
  88. TEST_ASSERT_EQUAL_MESSAGE(0, std::distance(frame.cbegin(), frame.cend()),
  89. "Frame with Command::SetDP should not have any data attached to it");
  90. }
  91. void test_dataframe_copy() {
  92. DataFrame frame(Command::Heartbeat);
  93. frame.version = 0x7f;
  94. DataFrame moved_frame(std::move(frame));
  95. TEST_ASSERT_EQUAL_MESSAGE(0x7f, moved_frame.version,
  96. "DataFrame should be movable object");
  97. TEST_ASSERT_MESSAGE(!std::is_copy_constructible<DataFrame>::value,
  98. "DataFrame should not be copyable");
  99. }
  100. void test_dataframe_raw_data() {
  101. {
  102. const std::vector<uint8_t> data = {0x55, 0xaa, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01};
  103. DataFrame frame(data.cbegin());
  104. TEST_ASSERT_MESSAGE(frame.commandEquals(Command::Heartbeat),
  105. "This message should be parsed as heartbeat");
  106. TEST_ASSERT_EQUAL_MESSAGE(0, frame.version,
  107. "This message should have version == 0");
  108. TEST_ASSERT_EQUAL_MESSAGE(1, frame.length,
  109. "Heartbeat message contains a single byte");
  110. TEST_ASSERT_EQUAL_MESSAGE(1, frame[0],
  111. "Heartbeat message contains a single 0x01");
  112. }
  113. {
  114. const std::vector<uint8_t> data = {0x55, 0xaa, 0x00, 0x07, 0x00, 0x05, 0x01, 0x01, 0x00, 0x01, 0x01, 0x0f};
  115. DataFrame frame(data.cbegin());
  116. TEST_ASSERT_MESSAGE(frame.commandEquals(Command::ReportDP),
  117. "This message should be parsed as data protocol");
  118. TEST_ASSERT_MESSAGE(datatype_same(frame, Type::BOOL),
  119. "This message should have boolean datatype attached to it");
  120. TEST_ASSERT_EQUAL_MESSAGE(5, frame.length,
  121. "Boolean DP contains 5 bytes");
  122. const DataProtocol<bool> dp(frame);
  123. TEST_ASSERT_EQUAL_MESSAGE(1, dp.id(), "This boolean DP id should be 1");
  124. TEST_ASSERT_MESSAGE(dp.value(), "This boolean DP value should be true");
  125. }
  126. //show_datatype(frame);
  127. //std::cout << "length=" << frame.length << std::endl;
  128. //test_hexdump("input", frame.serialize());
  129. //std::cout << "[" << millis() << "] -------------------bad dp frame----------------" << std::endl;
  130. //DataFrame bad_dp_frame(Command::ReportDP, DataProtocol<uint32_t>(0x03, 255).serialize());
  131. //show_datatype(bad_dp_frame);
  132. //std::cout << "length=" << bad_dp_frame.length << std::endl;
  133. //test_hexdump("input", bad_dp_frame.serialize());
  134. }
  135. class BufferedStream : public Stream {
  136. public:
  137. // Print interface
  138. size_t write(uint8_t c) {
  139. _buffer.push((int)c);
  140. return 1;
  141. }
  142. size_t write(const unsigned char* data, unsigned long size) {
  143. for (size_t n = 0; n < size; ++n) {
  144. _buffer.push(data[n]);
  145. }
  146. return size;
  147. }
  148. int availableForWrite() { return 1; }
  149. void flush() {
  150. while (!_buffer.empty()) {
  151. _buffer.pop();
  152. }
  153. }
  154. // Stream interface
  155. int available() {
  156. return _buffer.size();
  157. }
  158. int read() {
  159. if (!_buffer.size()) return -1;
  160. int c = _buffer.front();
  161. _buffer.pop();
  162. return c;
  163. }
  164. int peek() {
  165. if (!_buffer.size()) return -1;
  166. return _buffer.front();
  167. }
  168. private:
  169. std::queue<int> _buffer;
  170. };
  171. void test_transport() {
  172. const std::vector<uint8_t> data = {0x55, 0xaa, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01};
  173. BufferedStream stream;
  174. stream.write(data.data(), data.size());
  175. Transport transport(stream);
  176. TEST_ASSERT_MESSAGE(transport.available(), "Available data");
  177. }
  178. int main(int argc, char** argv) {
  179. UNITY_BEGIN();
  180. RUN_TEST(test_states);
  181. RUN_TEST(test_static_dataframe_bool);
  182. RUN_TEST(test_static_dataframe_int);
  183. RUN_TEST(test_static_dataframe_heartbeat);
  184. RUN_TEST(test_dataframe_const);
  185. RUN_TEST(test_dataframe_copy);
  186. RUN_TEST(test_dataframe_raw_data);
  187. RUN_TEST(test_transport);
  188. UNITY_END();
  189. }