From f3067bfd2e51dedacfc74101891fc9d0accce32a Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 11 Aug 2026 12:23:07 +0900 Subject: [PATCH] Add legacy contracts Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- tests/firmware/test_legacy_descriptors.cpp | 98 ++++++++++++++++++++++ tests/firmware/test_support.h | 38 +++++++++ 2 files changed, 136 insertions(+) create mode 100644 tests/firmware/test_legacy_descriptors.cpp create mode 100644 tests/firmware/test_support.h diff --git a/tests/firmware/test_legacy_descriptors.cpp b/tests/firmware/test_legacy_descriptors.cpp new file mode 100644 index 0000000..e66bd77 --- /dev/null +++ b/tests/firmware/test_legacy_descriptors.cpp @@ -0,0 +1,98 @@ +#include "test_support.h" + +#include +#include +#include + +#include "../../switch_pro_descriptors.h" + +namespace { + +template +bool bytes_equal( + const uint8_t (&actual)[ActualSize], + const uint8_t (&expected)[ExpectedSize]) { + return ActualSize == ExpectedSize && + std::memcmp(actual, expected, ExpectedSize) == 0; +} + +bool legacy_device_descriptor_matches_exact_bytes() { + // Given: the captured legacy device descriptor bytes. + static constexpr uint8_t expected[] = { + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x7E, + 0x05, 0x09, 0x20, 0x10, 0x02, 0x01, 0x02, 0x03, 0x01, + }; + + // When: the compiled legacy descriptor is inspected. + // Then: its identity and all 18 bytes remain unchanged. + CHECK(sizeof(switch_pro_device_descriptor) == 18); + CHECK(bytes_equal(switch_pro_device_descriptor, expected)); + return true; +} + +bool legacy_configuration_descriptor_matches_exact_bytes() { + // Given: the captured single-interface legacy configuration. + static constexpr uint8_t expected[] = { + 0x09, 0x02, 0x29, 0x00, 0x01, 0x01, 0x00, 0xA0, 0xFA, + 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, + 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0xCB, 0x00, + 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x08, + 0x07, 0x05, 0x01, 0x03, 0x40, 0x00, 0x08, + }; + + // When: the compiled legacy configuration is inspected. + // Then: the interface and both interrupt endpoints remain byte-identical. + CHECK(sizeof(switch_pro_configuration_descriptor) == 41); + CHECK(bytes_equal(switch_pro_configuration_descriptor, expected)); + return true; +} + +bool legacy_hid_report_descriptor_matches_exact_bytes() { + // Given: the complete captured 203-byte legacy HID report descriptor. + static constexpr uint8_t expected[] = { + 0x05, 0x01, 0x15, 0x00, 0x09, 0x04, 0xA1, 0x01, 0x85, 0x30, 0x05, 0x01, 0x05, 0x09, 0x19, 0x01, + 0x29, 0x0A, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0A, 0x55, 0x00, 0x65, 0x00, 0x81, 0x02, + 0x05, 0x09, 0x19, 0x0B, 0x29, 0x0E, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x81, 0x02, + 0x75, 0x01, 0x95, 0x02, 0x81, 0x03, 0x0B, 0x01, 0x00, 0x01, 0x00, 0xA1, 0x00, 0x0B, 0x30, 0x00, + 0x01, 0x00, 0x0B, 0x31, 0x00, 0x01, 0x00, 0x0B, 0x32, 0x00, 0x01, 0x00, 0x0B, 0x35, 0x00, 0x01, + 0x00, 0x15, 0x00, 0x27, 0xFF, 0xFF, 0x00, 0x00, 0x75, 0x10, 0x95, 0x04, 0x81, 0x02, 0xC0, 0x0B, + 0x39, 0x00, 0x01, 0x00, 0x15, 0x00, 0x25, 0x07, 0x35, 0x00, 0x46, 0x3B, 0x01, 0x65, 0x14, 0x75, + 0x04, 0x95, 0x01, 0x81, 0x02, 0x05, 0x09, 0x19, 0x0F, 0x29, 0x12, 0x15, 0x00, 0x25, 0x01, 0x75, + 0x01, 0x95, 0x04, 0x81, 0x02, 0x75, 0x08, 0x95, 0x34, 0x81, 0x03, 0x06, 0x00, 0xFF, 0x85, 0x21, + 0x09, 0x01, 0x75, 0x08, 0x95, 0x3F, 0x81, 0x03, 0x85, 0x81, 0x09, 0x02, 0x75, 0x08, 0x95, 0x3F, + 0x81, 0x03, 0x85, 0x01, 0x09, 0x03, 0x75, 0x08, 0x95, 0x3F, 0x91, 0x83, 0x85, 0x10, 0x09, 0x04, + 0x75, 0x08, 0x95, 0x3F, 0x91, 0x83, 0x85, 0x80, 0x09, 0x05, 0x75, 0x08, 0x95, 0x3F, 0x91, 0x83, + 0x85, 0x82, 0x09, 0x06, 0x75, 0x08, 0x95, 0x3F, 0x91, 0x83, 0xC0, + }; + + // When: the compiled legacy HID descriptor is inspected. + // Then: every report item remains byte-identical. + CHECK(sizeof(switch_pro_report_descriptor) == 203); + CHECK(bytes_equal(switch_pro_report_descriptor, expected)); + return true; +} + +bool legacy_string_descriptors_match_exact_bytes() { + // Given: the legacy language, manufacturer, product, and serial strings. + static constexpr uint8_t language[] = {0x09, 0x04}; + static constexpr uint8_t manufacturer[] = "Nintendo Co., Ltd."; + static constexpr uint8_t product[] = "Pro Controller"; + static constexpr uint8_t version[] = "000000000001"; + + // When: the compiled string tables are inspected. + // Then: every string byte and terminator remains unchanged. + CHECK(bytes_equal(switch_pro_string_language, language)); + CHECK(bytes_equal(switch_pro_string_manufacturer, manufacturer)); + CHECK(bytes_equal(switch_pro_string_product, product)); + CHECK(bytes_equal(switch_pro_string_version, version)); + return true; +} + +} // namespace + +void run_legacy_descriptor_tests(TestRunner& runner) { + runner.run("legacy device descriptor exact bytes", legacy_device_descriptor_matches_exact_bytes); + runner.run("legacy configuration descriptor exact bytes", legacy_configuration_descriptor_matches_exact_bytes); + runner.run("legacy HID report descriptor exact bytes", legacy_hid_report_descriptor_matches_exact_bytes); + runner.run("legacy string descriptors exact bytes", legacy_string_descriptors_match_exact_bytes); +} diff --git a/tests/firmware/test_support.h b/tests/firmware/test_support.h new file mode 100644 index 0000000..8b47685 --- /dev/null +++ b/tests/firmware/test_support.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +class TestRunner { +public: + void run(const char* name, bool (*test)()) { + if (test()) { + std::printf("PASS %s\n", name); + return; + } + + ++failures_; + std::printf("FAIL %s\n", name); + } + + int result() const { + return failures_ == 0 ? 0 : 1; + } + +private: + int failures_ = 0; +}; + +#define CHECK(condition) \ + do { \ + if (!(condition)) { \ + std::fprintf(stderr, " %s:%d: %s\n", __FILE__, __LINE__, #condition); \ + return false; \ + } \ + } while (false) + +void run_legacy_descriptor_tests(TestRunner& runner); +void run_switch2_command_tests(TestRunner& runner); +void run_switch2_descriptor_tests(TestRunner& runner); +void run_switch2_report_tests(TestRunner& runner); +void run_switch_input_tests(TestRunner& runner); +void run_switch_uart_protocol_tests(TestRunner& runner);