Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tests] Increase QMK test coverage #13789

Merged
merged 10 commits into from
Nov 22, 2021
Merged

Conversation

KarlK90
Copy link
Member

@KarlK90 KarlK90 commented Jul 30, 2021

Description

This PR enhances the current unit-testing integration testing facilities and adds additional tests:

  • All tests use an isolated per-test keymap instead of a global shared keymap in keymap.c the usage goes like this:
/* Define keys like this: layer, column, row, keycode */
auto       key_a      = KeymapKey(0, 0, 0, KC_A);
auto       key_lshift = KeymapKey(0, 1, 1, KC_LSFT);

/* Add keys to keymap for this test */
set_keymap({key_a, key_lshift});

key_a.press();
key_a.release();
key_lshift.press();
key_lshift.release();
  • Tests that fail provide a lot more context on the events that happened during the execution.
  • Tests were added:
    • basic key-presses
    • mod-taps and layer taps with different tap-hold configurations
    • one-shot mods and layers

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Keyboard (addition or update)
  • Keymap/layout/userspace (addition or update)
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project: C, Python
  • I have read the PR Checklist document and have made the appropriate changes.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

@github-actions github-actions bot added the core label Jul 30, 2021
@KarlK90 KarlK90 force-pushed the add-qmk-unit-tests branch from b30de2f to c6b2db0 Compare July 30, 2021 12:01
@KarlK90 KarlK90 force-pushed the add-qmk-unit-tests branch 2 times, most recently from ab5b42e to b29bde3 Compare August 14, 2021 14:11
@KarlK90 KarlK90 changed the title [DRAFT][Tests] Increase QMK unit-test coverage [Tests] Increase QMK unit-test coverage Aug 14, 2021
@KarlK90 KarlK90 marked this pull request as ready for review August 14, 2021 14:12
@KarlK90 KarlK90 changed the title [Tests] Increase QMK unit-test coverage [Tests] Increase QMK test coverage Aug 14, 2021
@KarlK90
Copy link
Member Author

KarlK90 commented Aug 14, 2021

This is now ready for review and a good starting point to add more test-cases.

I haven't figured out a good way to run the different configurations in one go as this requires a change to the way the tests are compiled and called by the make system. Maybe one of the reviewers has a killer idea? The way QMK currently works would require several differently configured testing binaries to be build and run. For instance one with the default mod-tap behavior, one with mod-tap-interrupt only, one with force-tap-hold etc.

@KarlK90
Copy link
Member Author

KarlK90 commented Aug 18, 2021

Every QMK configuration that needs a different binary is now split out into an individual testing binary, so all tests can be run simultaneously. 💪

@KarlK90 KarlK90 force-pushed the add-qmk-unit-tests branch 2 times, most recently from 319044d to 9f9a9a6 Compare August 18, 2021 18:41
@drashna drashna requested a review from a team August 19, 2021 18:10
@drashna
Copy link
Member

drashna commented Sep 27, 2021

Can the "in progress" label be removed here?

@KarlK90
Copy link
Member Author

KarlK90 commented Sep 27, 2021

Yes it can!

@drashna
Copy link
Member

drashna commented Sep 27, 2021

Looks like this is erroring out on:

Unexpected mock function call - returning directly.
    Function call: send_keyboard_mock(@0x5582251ce890 Keyboard Report: Mods (0) Keys ()
)
Google Mock tried the following 2 expectations, but none matched:

tests/basic/test_action_layer.cpp:286: tried expectation #0: EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_RALT)))...
  Expected arg #0: is equal to Keyboard Report: Mods (64) Keys ()

           Actual: Keyboard Report: Mods (0) Keys ()

         Expected: to be called once
           Actual: never called - unsatisfied and active
tests/basic/test_action_layer.cpp:287: tried expectation #1: EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_RALT, KC_9)))...

Running this from the docker container.

@KarlK90
Copy link
Member Author

KarlK90 commented Sep 27, 2021

Yes, this is expected, as the test documents false buggy behavior and was added in d50dcaf.

@drashna
Copy link
Member

drashna commented Sep 27, 2021

Well, specifically it is causing one of the tests to fail, which is my concern.

[  PASSED  ] 49 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] ActionLayer.LayerTapReleasedBeforeKeypressReleaseWithModifiers

@KarlK90
Copy link
Member Author

KarlK90 commented Sep 27, 2021

Yup, that is the one I added in the commit. It is an edge-case which doesnt happen to often on ansi-us layouts and the like. My reasoning was that I rather document the expected behaviour then what QMK currently does. Which is removing the modifier from the report on a layer change, altough it should not be modified because the key adding the modifier is still pressed. This results on a german layout in ((((<layer release>8888 instead of ((((<layer release>((((

@drashna drashna requested a review from a team September 29, 2021 18:59
tmk_core/native.mk Outdated Show resolved Hide resolved

void TestLogger::reset() { this->m_log.str(""); };

void TestLogger::print_log() { std::cerr << this->m_log.str(); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if this somehow took advantage of #13556, rather than it being its own entity.

Maybe binding int8_t sendchar(uint8_t c) to print to the same buffer, or using the debug macros instead of piping to std::cerr?

From a quick skim of the PR, the high level is that you want to only dump log on errors? I could potentially see it being none/errors/all, with a nicer interface than the current DEBUG=.

@KarlK90 KarlK90 force-pushed the add-qmk-unit-tests branch from 674763f to f15f680 Compare October 21, 2021 20:32
@drashna drashna requested review from tzarc and a team October 23, 2021 05:13
set_keymap({layer_key});

/* Press and release MO, nothing should happen. */
/* TODO: Should not send empty report! */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can come up with better wording, by all means -- it's just so it's obvious that it's not a problem with the test, but with QMK itself.

Also, please change the other comment locations that have the same issue.

Suggested change
/* TODO: Should not send empty report! */
/* TODO: QMK currently sends an empty report even if nothing needs to be reported to the host! */


set_keymap({layer_key});

/* Press and release TG. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply a similar transformation where appropriate.

Suggested change
/* Press and release TG. */
/* Press TG. Layer state should not change as it's applied on release. */

EXPECT_TRUE(layer_state_is(0));
testing::Mock::VerifyAndClearExpectations(&driver);

/* TODO: Should not send empty report! */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply a similar transformation where appropriate.

Suggested change
/* TODO: Should not send empty report! */
/* Release TG */
/* TODO: <as per whatever wording you come up with from previous comment> */

EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
layer_key.press();
run_one_scan_loop();
EXPECT_TRUE(layer_state_is(0)); /* This is wrong? */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably layer_state_is should probably be something like layer_state_has -- it checks for a specific layer, ignoring the state of others.
In this specific case, layer_state_is(1) should also be true, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly but it is actually 0 which should be false, very curios. I'll add the correct expected behavior but set the test to be ignored and collect those in a separate issue.

Comment on lines 232 to 266
// TEST_F(ActionLayer, LayerTapToggleWithKeypress) {
// TestDriver driver;
// KeymapKey layer_key = KeymapKey{0, 0, 0, TT(1)};

// /* These keys must have the same position in the matrix, only the layer is different. */
// KeymapKey regular_key = KeymapKey{0, 1, 0, KC_A};
// set_keymap({layer_key, regular_key, KeymapKey{1, 1, 0, KC_B}});

// /* Press TT. */
// /* TODO: Should not send empty report! */
// EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0);
// layer_key.press();
// run_one_scan_loop();
// EXPECT_TRUE(layer_state_is(1));
// testing::Mock::VerifyAndClearExpectations(&driver);

// EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))).Times(1);
// regular_key.press();
// run_one_scan_loop();
// EXPECT_TRUE(layer_state_is(1));
// testing::Mock::VerifyAndClearExpectations(&driver);

// EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1);
// regular_key.release();
// run_one_scan_loop();
// EXPECT_TRUE(layer_state_is(1));
// testing::Mock::VerifyAndClearExpectations(&driver);

// /* TODO: Should not send empty report! */
// EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(1);
// layer_key.release();
// run_one_scan_loop();
// EXPECT_TRUE(layer_state_is(0));
// testing::Mock::VerifyAndClearExpectations(&driver);
// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What reason prevents this scenario from working?
The sequence looks correct to me?

}

TEST_F(DefaultTapHold, tap_mod_tap_hold_key_two_times) {
GTEST_SKIP() << "Keymap out of bounds access, uncomment for diagnostics!";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify, here? Testing bug? QMK bug?

}

TEST_F(DefaultTapHold, tap_mod_tap_hold_key_twice_and_hold_on_second_time) {
GTEST_SKIP() << "Keymap out of bounds access, uncomment for diagnostics!";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify, here? Testing bug? QMK bug?

tmk_core/native.mk Outdated Show resolved Hide resolved
@KarlK90
Copy link
Member Author

KarlK90 commented Nov 1, 2021

Thanks @tzarc and @zvecr for the feedback, I'll have more time next week during my holiday. Looking forward to getting this merged.

@drashna
Copy link
Member

drashna commented Nov 19, 2021

Some merge conflicts

@tzarc tzarc merged commit b6054c0 into qmk:develop Nov 22, 2021
tzarc added a commit that referenced this pull request Nov 22, 2021
@tzarc
Copy link
Member

tzarc commented Nov 22, 2021

As discussed on Discord, reverted thru commit 7746aef.
Follow-up PR to come.

cadusk pushed a commit to cadusk/qmk_firmware that referenced this pull request Dec 2, 2021
* qmk/develop: (80 commits)
  Remove use of __flash due to LTO issues (qmk#15268)
  Revert "handwired/split89 Layout Macro Refactor (qmk#15210)" (qmk#15284)
  New Keyboard: TGR Jane CE (qmk#14713)
  Portal 66 Layout Macro Refactor (qmk#15255)
  Pluckey: Fix QMK Configurator Implementation (qmk#15254)
  [Tests] Increase QMK test coverage take 2 (qmk#15269)
  Ignore exit codes for formatters (qmk#15276)
  [Keyboard] Disable features on SplitKB boards to fit under size (qmk#15262)
  Ignore exit codes for formatters (qmk#15275)
  Ignore deleted files when formatting codebase (qmk#15274)
  qmk format-python - filter for Python files (qmk#15271)
  Revert "[Tests] Increase QMK test coverage (qmk#13789)"
  [Tests] Increase QMK test coverage (qmk#13789)
  [Docs] Squeezing space out of AVR (qmk#15243)
  Add uint to char functions (qmk#15244)
  [Keyboard] Disable console on Keebio foldkb and iris rev3 (qmk#15260)
  layer_combo → sd_combo (qmk#15266)
  [Keymap] Disable console on Sofle default keymap (qmk#15261)
  [Keyboard] Enable LTO on viktus/sp_mini via keymap (qmk#15263)
  Macros in JSON keymaps (qmk#14374)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants