Skip to content

Commit b03f5bb

Browse files
committed
Adds CharacterToKeyIndexRoundtrip tests for all units
- Verifies toKeyIndex and character_to_mode_bits consistency for all characters - Checks normal (a-z), shift (A-Z), sym, and Fn mode bits - Validates Fn character roundtrip for CardKB and FacesQWERTY
1 parent 58097d8 commit b03f5bb

4 files changed

Lines changed: 186 additions & 2 deletions

File tree

test/embedded/test_cardkb/cardkb_test.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <googletest/test_template.hpp>
1414
#include <googletest/test_helper.hpp>
1515
#include <unit/unit_CardKB.hpp>
16-
#include <cmath>
16+
#include <cstring>
1717

1818
using namespace m5::unit::googletest;
1919
using namespace m5::unit;
@@ -82,3 +82,55 @@ TEST_F(TestCardKB, M5UnitUnifiedFirmware)
8282
EXPECT_EQ(mode, m);
8383
}
8484
}
85+
86+
// Bidirectional conversion: toKeyIndex(ch) must return a valid key index for every
87+
// character that the unit can produce, and the mapping must be consistent.
88+
TEST_F(TestCardKB, CharacterToKeyIndexRoundtrip)
89+
{
90+
SCOPED_TRACE(ustr);
91+
92+
// Every recognized character must have valid key index AND non-zero mode bits
93+
for (int c = 1; c < 256; ++c) {
94+
char ch = static_cast<char>(c);
95+
auto kidx = unit->toKeyIndex(ch);
96+
if (kidx == 0xFF) {
97+
continue;
98+
}
99+
EXPECT_LT(kidx, UnitCardKB::NUMBER_OF_KEYS)
100+
<< "toKeyIndex(0x" << std::hex << c << ") returned out-of-range key index " << (int)kidx;
101+
102+
auto mbits = UnitCardKB::character_to_mode_bits(ch);
103+
EXPECT_NE(mbits, 0) << "character_to_mode_bits(0x" << std::hex << c << ") returned 0 but toKeyIndex returned "
104+
<< (int)kidx;
105+
106+
// Mode-specific consistency: verify each recognized character has the expected mode bit
107+
// normal=0x01, shift=0x02, sym=0x04, fn=0x08
108+
if (ch >= 'a' && ch <= 'z') {
109+
EXPECT_TRUE(mbits & 0x01) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing normal bit";
110+
}
111+
if (ch >= 'A' && ch <= 'Z') {
112+
EXPECT_TRUE(mbits & 0x02) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing shift bit";
113+
}
114+
// Symbol-only characters (not in normal/shift) must have sym bit
115+
if (std::strchr("!@#$%^&*(){}[]|\\~`?/<>=+_-;:\"'", ch) && !(mbits & 0x03)) {
116+
EXPECT_TRUE(mbits & 0x04) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing sym bit";
117+
}
118+
}
119+
120+
// Verify Fn characters (>= 0x80): toKeyIndex must return the correct key
121+
// CardKB Fn values are key_index + 128, so roundtrip must hold
122+
for (uint8_t kidx = 0; kidx < UnitCardKB::NUMBER_OF_KEYS; ++kidx) {
123+
uint8_t fn_char = kidx + 128;
124+
auto result = unit->toKeyIndex(static_cast<char>(fn_char));
125+
if (result == 0xFF) {
126+
continue;
127+
}
128+
EXPECT_EQ(result, kidx) << "Fn char 0x" << std::hex << (int)fn_char << " mapped to key " << (int)result
129+
<< " instead of " << (int)kidx;
130+
131+
// Fn characters must have function mode bit (0x08)
132+
auto mbits = UnitCardKB::character_to_mode_bits(static_cast<char>(fn_char));
133+
EXPECT_EQ(mbits & 0x08, 0x08) << "Fn char 0x" << std::hex << (int)fn_char << " mode_bits=" << (int)mbits
134+
<< " missing function bit";
135+
}
136+
}

test/embedded/test_cardkb2/cardkb2_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <googletest/test_template.hpp>
1616
#include <googletest/test_helper.hpp>
1717
#include <unit/unit_CardKB2.hpp>
18+
#include <unit/unit_CardKB2_defs.hpp>
19+
#include <cstring>
1820

1921
using namespace m5::unit::googletest;
2022
using namespace m5::unit;
@@ -84,3 +86,47 @@ TEST_F(TestCardKB2, Update)
8486
// Still no key pressed
8587
EXPECT_EQ(unit->getchar(), 0);
8688
}
89+
90+
// Bidirectional: toKeyIndex(ch) and character_to_mode_bits(ch) must be consistent
91+
// for every character across all modifier modes (normal, shift, sym, fn)
92+
TEST_F(TestCardKB2, CharacterToKeyIndexRoundtrip)
93+
{
94+
SCOPED_TRACE(ustr);
95+
96+
// Every recognized character must have valid key index AND non-zero mode bits
97+
for (int c = 1; c < 256; ++c) {
98+
char ch = static_cast<char>(c);
99+
auto kidx = unit->toKeyIndex(ch);
100+
if (kidx == 0xFF) {
101+
continue;
102+
}
103+
EXPECT_LT(kidx, m5::unit::cardkb2::NUMBER_OF_KEYS)
104+
<< "toKeyIndex(0x" << std::hex << c << ") returned out-of-range key index " << (int)kidx;
105+
106+
auto mbits = m5::unit::cardkb2::character_to_mode_bits(ch);
107+
EXPECT_NE(mbits, 0) << "character_to_mode_bits(0x" << std::hex << c << ") returned 0 but toKeyIndex returned "
108+
<< (int)kidx;
109+
110+
// Mode-specific consistency:
111+
// normal (bit0=0x01), shift (bit1=0x02), sym (bit2=0x04), fn (bit3=0x08)
112+
if (ch >= 'a' && ch <= 'z') {
113+
EXPECT_TRUE(mbits & 0x01) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing normal bit";
114+
}
115+
if (ch >= 'A' && ch <= 'Z') {
116+
EXPECT_TRUE(mbits & 0x02) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing shift bit";
117+
}
118+
if (std::strchr("!@#$%^&*(){}[]|\\~`?/<>=+_-;:\"'", ch) && !(mbits & 0x03)) {
119+
EXPECT_TRUE(mbits & 0x04) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing sym bit";
120+
}
121+
}
122+
123+
// Verify Fn characters: every Fn char must map to valid key index
124+
for (int c = 128; c < 256; ++c) {
125+
auto kidx = unit->toKeyIndex(static_cast<char>(c));
126+
if (kidx == 0xFF) {
127+
continue;
128+
}
129+
EXPECT_LT(kidx, m5::unit::cardkb2::NUMBER_OF_KEYS)
130+
<< "Fn char 0x" << std::hex << c << " mapped to out-of-range key index " << (int)kidx;
131+
}
132+
}

test/embedded/test_cardkb2_uart/cardkb2_uart_test.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <googletest/test_template.hpp>
1818
#include <googletest/test_helper.hpp>
1919
#include <unit/unit_CardKB2UART.hpp>
20+
#include <unit/unit_CardKB2_defs.hpp>
21+
#include <cstring>
2022

2123
using namespace m5::unit::googletest;
2224
using namespace m5::unit;
@@ -118,3 +120,43 @@ TEST_F(TestCardKB2UART, Update)
118120
EXPECT_EQ(unit->getchar(), 0);
119121
EXPECT_EQ(unit->nowBits(), 0U);
120122
}
123+
124+
// Bidirectional: toKeyIndex(ch) and character_to_mode_bits(ch) must be consistent
125+
// for every character across all modifier modes (normal, shift, sym, fn)
126+
TEST_F(TestCardKB2UART, CharacterToKeyIndexRoundtrip)
127+
{
128+
SCOPED_TRACE(ustr);
129+
130+
for (int c = 1; c < 256; ++c) {
131+
char ch = static_cast<char>(c);
132+
auto kidx = unit->toKeyIndex(ch);
133+
if (kidx == 0xFF) {
134+
continue;
135+
}
136+
EXPECT_LT(kidx, m5::unit::cardkb2::NUMBER_OF_KEYS)
137+
<< "toKeyIndex(0x" << std::hex << c << ") returned out-of-range key index " << (int)kidx;
138+
139+
auto mbits = m5::unit::cardkb2::character_to_mode_bits(ch);
140+
EXPECT_NE(mbits, 0) << "character_to_mode_bits(0x" << std::hex << c << ") returned 0 but toKeyIndex returned "
141+
<< (int)kidx;
142+
143+
if (ch >= 'a' && ch <= 'z') {
144+
EXPECT_TRUE(mbits & 0x01) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing normal bit";
145+
}
146+
if (ch >= 'A' && ch <= 'Z') {
147+
EXPECT_TRUE(mbits & 0x02) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing shift bit";
148+
}
149+
if (std::strchr("!@#$%^&*(){}[]|\\~`?/<>=+_-;:\"'", ch) && !(mbits & 0x03)) {
150+
EXPECT_TRUE(mbits & 0x04) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing sym bit";
151+
}
152+
}
153+
154+
for (int c = 128; c < 256; ++c) {
155+
auto kidx = unit->toKeyIndex(static_cast<char>(c));
156+
if (kidx == 0xFF) {
157+
continue;
158+
}
159+
EXPECT_LT(kidx, m5::unit::cardkb2::NUMBER_OF_KEYS)
160+
<< "Fn char 0x" << std::hex << c << " mapped to out-of-range key index " << (int)kidx;
161+
}
162+
}

test/embedded/test_faces/faces_test.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <googletest/test_template.hpp>
1414
#include <googletest/test_helper.hpp>
1515
#include <unit/unit_FacesQWERTY.hpp>
16-
#include <cmath>
16+
#include <cstring>
1717

1818
using namespace m5::unit::googletest;
1919
using namespace m5::unit;
@@ -81,3 +81,47 @@ TEST_F(TestFacesQWERTY, M5UnitUnifiedFirmware)
8181
EXPECT_EQ(mode, m);
8282
}
8383
}
84+
85+
TEST_F(TestFacesQWERTY, CharacterToKeyIndexRoundtrip)
86+
{
87+
SCOPED_TRACE(ustr);
88+
89+
for (int c = 1; c < 256; ++c) {
90+
char ch = static_cast<char>(c);
91+
auto kidx = unit->toKeyIndex(ch);
92+
if (kidx == 0xFF) {
93+
continue;
94+
}
95+
EXPECT_LT(kidx, UnitFacesQWERTY::NUMBER_OF_KEYS)
96+
<< "toKeyIndex(0x" << std::hex << c << ") returned out-of-range key index " << (int)kidx;
97+
98+
auto mbits = UnitFacesQWERTY::character_to_mode_bits(ch);
99+
EXPECT_NE(mbits, 0) << "character_to_mode_bits(0x" << std::hex << c << ") returned 0 but toKeyIndex returned "
100+
<< (int)kidx;
101+
102+
if (ch >= 'a' && ch <= 'z') {
103+
EXPECT_TRUE(mbits & 0x01) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing normal bit";
104+
}
105+
if (ch >= 'A' && ch <= 'Z') {
106+
EXPECT_TRUE(mbits & 0x02) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing shift bit";
107+
}
108+
if (std::strchr("!@#$%^&*(){}[]|\\~`?/<>=+_-;:\"'", ch) && !(mbits & 0x03)) {
109+
EXPECT_TRUE(mbits & 0x04) << "char '" << ch << "' mode_bits=" << (int)mbits << " missing sym bit";
110+
}
111+
}
112+
113+
// Verify Fn characters (>= 0x80): roundtrip must hold
114+
for (uint8_t kidx = 0; kidx < UnitFacesQWERTY::NUMBER_OF_KEYS; ++kidx) {
115+
uint8_t fn_char = kidx + 128;
116+
auto result = unit->toKeyIndex(static_cast<char>(fn_char));
117+
if (result == 0xFF) {
118+
continue;
119+
}
120+
EXPECT_EQ(result, kidx) << "Fn char 0x" << std::hex << (int)fn_char << " mapped to key " << (int)result
121+
<< " instead of " << (int)kidx;
122+
123+
auto mbits = UnitFacesQWERTY::character_to_mode_bits(static_cast<char>(fn_char));
124+
EXPECT_EQ(mbits & 0x08, 0x08) << "Fn char 0x" << std::hex << (int)fn_char << " mode_bits=" << (int)mbits
125+
<< " missing function bit";
126+
}
127+
}

0 commit comments

Comments
 (0)