From 5c100cf36152a336e5b1f042988be98ce1aa3952 Mon Sep 17 00:00:00 2001 From: Edward Hesketh Date: Wed, 21 Aug 2024 16:27:41 +0100 Subject: [PATCH] feat: add new tests, and fix the layer functions --- CMakeLists.txt | 12 +++ include/squirrel_quantum.h | 38 +++++--- src/squirrel_quantum.c | 41 ++++++-- ...er_activate_deactivate_get_consumer_code.c | 24 +++++ tests/key.c | 49 +++++++++- ...eyboard_activate_deactivate_get_modifier.c | 37 +++++++ tests/keyboard_activate_deactivate_keycode.c | 23 +++++ tests/layer_press_release.c | 96 ++++++++++++------- tests/quantum_passthrough_press_release.c | 79 ++++++++++++--- 9 files changed, 327 insertions(+), 72 deletions(-) create mode 100644 tests/consumer_activate_deactivate_get_consumer_code.c create mode 100644 tests/keyboard_activate_deactivate_get_modifier.c create mode 100644 tests/keyboard_activate_deactivate_keycode.c diff --git a/CMakeLists.txt b/CMakeLists.txt index bfdd61b..f22dec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,18 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Testing") add_executable(layer_press_release tests/layer_press_release.c) target_link_libraries(layer_press_release squirrel) add_test(NAME layer_press_release COMMAND layer_press_release) + + add_executable(consumer_activate_deactivate_get_consumer_code tests/consumer_activate_deactivate_get_consumer_code.c) + target_link_libraries(consumer_activate_deactivate_get_consumer_code squirrel) + add_test(NAME consumer_activate_deactivate_get_consumer_code COMMAND consumer_activate_deactivate_get_consumer_code) + + add_executable(keyboard_activate_deactivate_keycode tests/keyboard_activate_deactivate_keycode.c) + target_link_libraries(keyboard_activate_deactivate_keycode squirrel) + add_test(NAME keyboard_activate_deactivate_keycode COMMAND keyboard_activate_deactivate_keycode) + + add_executable(keyboard_activate_deactivate_get_modifier tests/keyboard_activate_deactivate_get_modifier.c) + target_link_libraries(keyboard_activate_deactivate_get_modifier squirrel) + add_test(NAME keyboard_activate_deactivate_get_modifier COMMAND keyboard_activate_deactivate_get_modifier) else() add_compile_options(-Os) # Enable size optimizations endif() diff --git a/include/squirrel_quantum.h b/include/squirrel_quantum.h index 269581f..51d916b 100644 --- a/include/squirrel_quantum.h +++ b/include/squirrel_quantum.h @@ -52,48 +52,56 @@ enum squirrel_error consumer_release(struct key *key, uint8_t layer, void **args); // quantum_passthrough_press passes the press action to the highest active layer -// below the current one. It expectes no extra args. +// below the current one. It expectes no extra args. Equivalent to KC_TRNS in +// QMK. enum squirrel_error quantum_passthrough_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); // quantum_passthrough_release passes the release action to the highest active -// layer below the current one. It expectes no extra args. +// layer below the current one. It expectes no extra args. Equivalent to KC_TRNS +// in QMK. enum squirrel_error quantum_passthrough_release(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); // layer_momentary_press activates the layer with the given index. It expects -// the layer number as the first uint8 argument. +// the layer number as the first uint8 argument. Equivalent to MO() in QMK. enum squirrel_error layer_momentary_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); // layer_momentary_release deactivates the layer with the given index. It -// expects the layer number as the first uint8 argument. +// expects the layer number as the first uint8 argument. Equivalent to MO() in +// QMK. enum squirrel_error layer_momentary_release(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); // layer_toggle_press toggles the layer with the given index. It expects the -// layer number as the first uint8 argument. +// layer number as the first uint8 argument. Equivalent to TG() in QMK. enum squirrel_error layer_toggle_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); -// layer_toggle_release does nothing at the moment. +// layer_toggle_release does nothing at the moment. It expects the layer number +// as a uint8 anyway - this is a placeholder for future functionality. +// Equivalent to TG() in QMK. enum squirrel_error layer_toggle_release(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args); -// layer_turn_on_press activates the layer with the given index. It expects the -// layer number as the first uint8 argument. -enum squirrel_error layer_turn_on_press(struct key *key, uint8_t layer, - uint8_t key_index, int arg_count, - void **args); +// layer_solo_press turns off all other layers than the layer with the given +// index. It expects the layer number as the first uint8 argument. Equivalent to +// TO() in QMK. +enum squirrel_error layer_solo_press(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args); -// layer_turn_on_release does nothing at the moment. -enum squirrel_error layer_turn_on_release(struct key *key, uint8_t layer, - uint8_t key_index, int arg_count, - void **args); +// layer_solo_release does nothing at the moment. It expects the layer number +// as a uint8 anyway - this is a placeholder for future functionality. +// Equivalent to TO() in QMK. +enum squirrel_error layer_solo_release(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args); #endif diff --git a/src/squirrel_quantum.c b/src/squirrel_quantum.c index cc34a55..b84f2ca 100644 --- a/src/squirrel_quantum.c +++ b/src/squirrel_quantum.c @@ -154,35 +154,64 @@ enum squirrel_error quantum_passthrough_release(struct key *key, uint8_t layer, enum squirrel_error layer_momentary_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; + uint8_t target_layer = *(uint8_t *)args[0]; + layers[target_layer].active = true; return ERR_NONE; } enum squirrel_error layer_momentary_release(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; + uint8_t target_layer = *(uint8_t *)args[0]; + layers[target_layer].active = false; return ERR_NONE; } enum squirrel_error layer_toggle_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; + uint8_t target_layer = *(uint8_t *)args[0]; + layers[target_layer].active = !layers[target_layer].active; return ERR_NONE; } enum squirrel_error layer_toggle_release(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; return ERR_NONE; } -enum squirrel_error layer_turn_on_press(struct key *key, uint8_t layer, - uint8_t key_index, int arg_count, - void **args) { +enum squirrel_error layer_solo_press(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; + uint8_t target_layer = *(uint8_t *)args[0]; + for (uint8_t i = 0; i < 16; i++) { + layers[i].active = false; + } + layers[target_layer].active = true; return ERR_NONE; } -enum squirrel_error layer_turn_on_release(struct key *key, uint8_t layer, - uint8_t key_index, int arg_count, - void **args) { +enum squirrel_error layer_solo_release(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args) { + if (arg_count != 1) { + return ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT; + }; return ERR_NONE; } diff --git a/tests/consumer_activate_deactivate_get_consumer_code.c b/tests/consumer_activate_deactivate_get_consumer_code.c new file mode 100644 index 0000000..8ac7d96 --- /dev/null +++ b/tests/consumer_activate_deactivate_get_consumer_code.c @@ -0,0 +1,24 @@ +#include "squirrel.h" +#include "squirrel_consumer.h" +#include "squirrel_key.h" +#include "squirrel_quantum.h" +#include +#include + +// test: consumer_activate_consumer_code + consumer_deactivate_consumer_code + +// consumer_get_consumer_code - in squirrel_consumer.c +int main() { + for (uint16_t test_consumer_code = 0; test_consumer_code <= 65534; + test_consumer_code++) { + // consumer_activate_consumer_code + consumer_activate_consumer_code(test_consumer_code); + if (consumer_get_consumer_code() != test_consumer_code) { + return 1; + } + // consumer_deactivate_consumer_code + consumer_deactivate_consumer_code(test_consumer_code); + if (consumer_get_consumer_code() != 0) { + return 2; + } + } +}; diff --git a/tests/key.c b/tests/key.c index f053093..aced271 100644 --- a/tests/key.c +++ b/tests/key.c @@ -45,7 +45,6 @@ int main() { init_keyboard(1); // press_key + release_key - uint8_t code1 = 0x0F; uint8_t code2 = 0xF0; @@ -65,6 +64,7 @@ int main() { layers[0].keys[0] = testkey; layers[0].active = true; + // check that arguments are correct, and in the correct order. enum squirrel_error err = press_key(0); if (err != ERR_NONE) { return 2; @@ -78,11 +78,54 @@ int main() { if (err != ERR_NONE) { return 4; } + if (test_result != 0) { + return 5; + } free(testkey.pressed_arguments); free(testkey.released_arguments); - // TODO: check_key + // check_key + + test_result = 1; + testkey.is_pressed = false; + check_key(0, true); // should call press_key + if (test_result != 0) { + return 6; + } + if (testkey.is_pressed != true) { + return 7; + } + + test_result = 1; + testkey.is_pressed = true; + check_key(0, false); // should call release_key + if (test_result != 0) { + return 8; + } + if (testkey.is_pressed != false) { + return 9; + } + + test_result = 1; + testkey.is_pressed = true; + check_key(0, true); // should not call press_key + if (test_result != 1) { + return 10; + } + if (testkey.is_pressed != true) { + return 11; + } + + test_result = 1; + testkey.is_pressed = false; + check_key(0, false); // should not call release_key + if (test_result != 1) { + return 12; + } + if (testkey.is_pressed != false) { + return 13; + } - return test_result; + return 0; } diff --git a/tests/keyboard_activate_deactivate_get_modifier.c b/tests/keyboard_activate_deactivate_get_modifier.c new file mode 100644 index 0000000..cd793fb --- /dev/null +++ b/tests/keyboard_activate_deactivate_get_modifier.c @@ -0,0 +1,37 @@ +#include "squirrel.h" +#include "squirrel_consumer.h" +#include "squirrel_key.h" +#include "squirrel_quantum.h" +#include +#include + +// test: keyboard_activate_modifier + keyboard_deactivate_modifier + +// keyboard_get_modifiers - in squirrel_keyboard.c +int main() { + for (uint8_t test_modifier = 0b00000001; test_modifier != 0b00000000; + test_modifier = test_modifier << 1) { + for (uint8_t test_modifier_2 = 0b10000000; test_modifier_2 != 0b00000000; + test_modifier_2 = test_modifier_2 >> 1) { + if (test_modifier == test_modifier_2) { // Skip if the same modifier + continue; + } + keyboard_activate_modifier(test_modifier); + if (keyboard_get_modifiers() != test_modifier) { + return 1; + } + keyboard_activate_modifier(test_modifier_2); + if (keyboard_get_modifiers() != (test_modifier | test_modifier_2)) { + return 2; + } + // keyboard_deactivate_modifier + keyboard_deactivate_modifier(test_modifier); + if (keyboard_get_modifiers() != test_modifier_2) { + return 3; + } + keyboard_deactivate_modifier(test_modifier_2); + if (keyboard_get_modifiers() != 0) { + return 4; + } + } + } +}; diff --git a/tests/keyboard_activate_deactivate_keycode.c b/tests/keyboard_activate_deactivate_keycode.c new file mode 100644 index 0000000..6e680ee --- /dev/null +++ b/tests/keyboard_activate_deactivate_keycode.c @@ -0,0 +1,23 @@ +#include "squirrel.h" +#include "squirrel_consumer.h" +#include "squirrel_key.h" +#include "squirrel_quantum.h" +#include +#include + +// test: keyboard_activate_keycode + keyboard_deactivate_keycode in +// squirrel_keyboard.c +int main() { + for (uint8_t test_keycode = 0; test_keycode <= 254; test_keycode++) { + // keyboard_activate_keycode + keyboard_activate_keycode(test_keycode); + if (keyboard_keycodes[test_keycode] != true) { + return 1; + } + // keyboard_deactivate_keycode + keyboard_deactivate_keycode(test_keycode); + if (keyboard_keycodes[test_keycode] != false) { + return 2; + } + } +}; diff --git a/tests/layer_press_release.c b/tests/layer_press_release.c index 515a0ba..4f1b447 100644 --- a/tests/layer_press_release.c +++ b/tests/layer_press_release.c @@ -10,8 +10,8 @@ // layer_momentary_release // layer_toggle_press // layer_toggle_release -// layer_turn_on_press -// layer_turn_on_release +// layer_solo_press +// layer_solo_release // in squirrel_quantum.c int main() { init_keyboard(1); @@ -35,11 +35,11 @@ int main() { if (err != ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT) { return 4; } - err = layer_turn_on_press(&test_key, 0, 0, 0, 0); // too few + err = layer_solo_press(&test_key, 0, 0, 0, 0); // too few if (err != ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT) { return 5; } - err = layer_turn_on_release(&test_key, 0, 0, 2, 0); // too many + err = layer_solo_release(&test_key, 0, 0, 2, 0); // too many if (err != ERR_KEY_FUNC_WRONG_ARGUMENT_COUNT) { return 6; } @@ -49,81 +49,103 @@ int main() { args[0] = &target_layer; // layer_momentary - layer_momentary_press(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + layer_momentary_press(&test_key, 0, 0, 1, + args); // should activate target_layer only + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 7; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 8; } - layer_momentary_release(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + for (uint8_t i = 0; i < 16; i++) { // activate all layers + layers[i].active = true; + } + layer_momentary_release(&test_key, 0, 0, 1, + args); // should deactivate target_layer only + for (uint8_t i = 0; i < 16; i++) { + if (!layers[i].active && + i != target_layer) { // if any other layers are not active, fail. return 9; } } - if (layers[target_layer].active) { + if (layers[target_layer].active) { // if target_layer is active, fail. return 10; } + for (uint8_t i = 0; i < 16; i++) { // deactivate all layers for next test + layers[i].active = false; + } // layer_toggle - layer_toggle_press(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + layer_toggle_press(&test_key, 0, 0, 1, args); // should activate target_layer + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 11; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 12; } - layer_toggle_press(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + layer_toggle_release(&test_key, 0, 0, 1, args); // should not deactivate + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 13; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 14; } - layer_toggle_release(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { + layer_toggle_press(&test_key, 0, 0, 1, + args); // should deactivate target_layer + for (uint8_t i = 0; i < 16; i++) { // if any other layers are active, fail. if (layers[i].active && i != target_layer) { return 15; } } - if (!layers[target_layer].active) { + if (layers[target_layer].active) { // if target_layer is active, fail. return 16; } - layers[target_layer].active = false; - // layer_turn_on - layer_turn_on_press(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + // layer_solo + for (uint8_t i = 0; i < 16; i++) { // turn on all layers + layers[i].active = true; + } + layer_solo_press(&test_key, 0, 0, 1, + args); // solo should turn off all layers except target_layer + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 17; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 18; } - layer_turn_on_press(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + layer_solo_press( + &test_key, 0, 0, 1, + args); // solo should not turn off target_layer if called again + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 19; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 20; } - layer_turn_on_release(&test_key, 0, 0, 1, args); - for (uint8_t i = 0; i < 17; i++) { - if (layers[i].active && i != target_layer) { + layer_solo_release(&test_key, 0, 0, 1, + args); // release should not do anything + for (uint8_t i = 0; i < 16; i++) { + if (layers[i].active && + i != target_layer) { // if any other layers are active, fail. return 21; } } - if (!layers[target_layer].active) { + if (!layers[target_layer].active) { // if target_layer is not active, fail. return 22; } free(args); diff --git a/tests/quantum_passthrough_press_release.c b/tests/quantum_passthrough_press_release.c index cefa2de..8ba978b 100644 --- a/tests/quantum_passthrough_press_release.c +++ b/tests/quantum_passthrough_press_release.c @@ -4,7 +4,8 @@ #include "squirrel_quantum.h" #include -uint8_t test_result = 1; +uint8_t test_result = 1; // 0 = pass, 1 = fail +bool bad_test = false; // true = fail enum squirrel_error test_press(struct key *key, uint8_t layer, uint8_t key_index, int arg_count, void **args) { @@ -19,6 +20,20 @@ enum squirrel_error test_release(struct key *key, uint8_t layer, return ERR_NONE; } +enum squirrel_error bad_test_press(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args) { + bad_test = true; + return ERR_NONE; +} + +enum squirrel_error bad_test_release(struct key *key, uint8_t layer, + uint8_t key_index, int arg_count, + void **args) { + bad_test = true; + return ERR_NONE; +} + // test: quantum_passthrough_press + quantum_passthrough_release test - in // squirrel_quantum.c int main() { @@ -29,32 +44,74 @@ int main() { testkey.pressed_argument_count = 0; testkey.released = test_release; testkey.released_argument_count = 0; - layers[0].keys[0] = testkey; + layers[0].keys[0] = testkey; // When testkey is pressed, the test is passing. struct key passthroughkey; passthroughkey.pressed = quantum_passthrough_press; passthroughkey.pressed_argument_count = 0; passthroughkey.released = quantum_passthrough_release; passthroughkey.released_argument_count = 0; - layers[1].keys[0] = passthroughkey; + layers[1].keys[0] = passthroughkey; // This is the key being tested. layers[0].active = true; layers[1].active = true; - enum squirrel_error err = press_key(0); - if (err != ERR_NONE) { + // Passthrough should press the key below it. + enum squirrel_error err = press_key(0); // Press the key. + if (err != ERR_NONE) { // If there is an error, the test fails. return 2; } - - if (test_result != 0) { + if (test_result != 0) { // If the testkey is not pressed, the test fails. return 3; } - test_result = 1; - err = release_key(0); - if (err != ERR_NONE) { + test_result = 1; // Reset the test result to failing again. + err = release_key(0); // Release the key. + if (err != ERR_NONE) { // If there is an error, the test fails. return 4; } + if (test_result != 0) { // If the testkey is not released, the test fails. + return 5; + } + + // Passthrough should fall through inactive layers + layers[0].active = true; // this layer contains the testkey. + layers[1].active = + false; // this layer contains the badtestkey and should be ignored. + layers[2].active = true; // this layer contains the passthrough key. + + layers[2].keys[0] = passthroughkey; + + struct key badtestkey; + badtestkey.pressed = bad_test_press; + badtestkey.pressed_argument_count = 0; + badtestkey.released = bad_test_release; + badtestkey.released_argument_count = 0; + layers[1].keys[0] = badtestkey; // When badtestkey is pressed, the test is + // failing. + + test_result = 1; // Reset the test result to failing again. + err = press_key(0); // Press the key. + if (err != ERR_NONE) { // If there is an error, the test fails. + return 6; + } + if (bad_test) { // If the badtestkey is pressed, the test fails. + return 7; + } + if (test_result != 0) { // If the testkey is not pressed, the test fails. + return 7; + } - return test_result; + test_result = 1; // Reset the test result to failing again. + err = release_key(0); // Release the key. + if (err != ERR_NONE) { // If there is an error, the test fails. + return 8; + } + if (bad_test) { // If the badtestkey is released, the test fails. + return 9; + } + if (test_result != 0) { // If the testkey is not released, the test fails. + return 10; + } + return 0; };