Skip to content

Commit

Permalink
Re-add encoder tests (#15312)
Browse files Browse the repository at this point in the history
Co-authored-by: Balz Guenat <[email protected]>
  • Loading branch information
drashna and BalzGuenat authored Nov 27, 2021
1 parent 4d0dd1e commit b3fc33f
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 0 deletions.
1 change: 1 addition & 0 deletions build_test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ include $(BUILDDEFS_PATH)/generic_features.mk
include $(PLATFORM_PATH)/common.mk
include $(TMK_PATH)/protocol.mk
include $(QUANTUM_PATH)/debounce/tests/rules.mk
include $(QUANTUM_PATH)/encoder/tests/rules.mk
include $(QUANTUM_PATH)/sequencer/tests/rules.mk
include $(PLATFORM_PATH)/test/rules.mk
ifneq ($(filter $(FULL_TESTS),$(TEST)),)
Expand Down
144 changes: 144 additions & 0 deletions quantum/encoder/tests/encoder_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/* Copyright 2021 Balz Guenat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <vector>
#include <algorithm>
#include <stdio.h>

extern "C" {
#include "encoder.h"
#include "encoder/tests/mock.h"
}

struct update {
int8_t index;
bool clockwise;
};

uint8_t uidx = 0;
update updates[32];

bool encoder_update_kb(uint8_t index, bool clockwise) {
updates[uidx % 32] = {index, clockwise};
uidx++;
return true;
}

bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
return encoder_read();
}

class EncoderTest : public ::testing::Test {};

TEST_F(EncoderTest, TestInit) {
uidx = 0;
encoder_init();
EXPECT_EQ(pinIsInputHigh[0], true);
EXPECT_EQ(pinIsInputHigh[1], true);
EXPECT_EQ(uidx, 0);
}

TEST_F(EncoderTest, TestOneClockwise) {
uidx = 0;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
setAndRead(1, true);

EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
}

TEST_F(EncoderTest, TestOneCounterClockwise) {
uidx = 0;
encoder_init();
setAndRead(1, false);
setAndRead(0, false);
setAndRead(1, true);
setAndRead(0, true);

EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, false);
}

TEST_F(EncoderTest, TestTwoClockwiseOneCC) {
uidx = 0;
encoder_init();
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
setAndRead(1, true);
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
setAndRead(1, true);
setAndRead(1, false);
setAndRead(0, false);
setAndRead(1, true);
setAndRead(0, true);

EXPECT_EQ(uidx, 3);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
EXPECT_EQ(updates[1].index, 0);
EXPECT_EQ(updates[1].clockwise, true);
EXPECT_EQ(updates[2].index, 0);
EXPECT_EQ(updates[2].clockwise, false);
}

TEST_F(EncoderTest, TestNoEarly) {
uidx = 0;
encoder_init();
// send 3 pulses. with resolution 4, that's not enough for a step.
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
EXPECT_EQ(uidx, 0);
// now send last pulse
setAndRead(1, true);
EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
}

TEST_F(EncoderTest, TestHalfway) {
uidx = 0;
encoder_init();
// go halfway
setAndRead(0, false);
setAndRead(1, false);
EXPECT_EQ(uidx, 0);
// back off
setAndRead(1, true);
setAndRead(0, true);
EXPECT_EQ(uidx, 0);
// go all the way
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
setAndRead(1, true);
// should result in 1 update
EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
}
143 changes: 143 additions & 0 deletions quantum/encoder/tests/encoder_tests_split.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/* Copyright 2021 Balz Guenat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <vector>
#include <algorithm>
#include <stdio.h>

extern "C" {
#include "encoder.h"
#include "encoder/tests/mock_split.h"
}

struct update {
int8_t index;
bool clockwise;
};

uint8_t uidx = 0;
update updates[32];

bool isLeftHand;

bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!isLeftHand) {
// this method has no effect on slave half
printf("ignoring update on right hand (%d,%s)\n", index, clockwise ? "CW" : "CC");
return true;
}
updates[uidx % 32] = {index, clockwise};
uidx++;
return true;
}

bool setAndRead(pin_t pin, bool val) {
setPin(pin, val);
return encoder_read();
}

class EncoderTest : public ::testing::Test {
protected:
void SetUp() override {
uidx = 0;
for (int i = 0; i < 32; i++) {
pinIsInputHigh[i] = 0;
pins[i] = 0;
}
}
};

TEST_F(EncoderTest, TestInitLeft) {
isLeftHand = true;
encoder_init();
EXPECT_EQ(pinIsInputHigh[0], true);
EXPECT_EQ(pinIsInputHigh[1], true);
EXPECT_EQ(pinIsInputHigh[2], false);
EXPECT_EQ(pinIsInputHigh[3], false);
EXPECT_EQ(uidx, 0);
}

TEST_F(EncoderTest, TestInitRight) {
isLeftHand = false;
encoder_init();
EXPECT_EQ(pinIsInputHigh[0], false);
EXPECT_EQ(pinIsInputHigh[1], false);
EXPECT_EQ(pinIsInputHigh[2], true);
EXPECT_EQ(pinIsInputHigh[3], true);
EXPECT_EQ(uidx, 0);
}

TEST_F(EncoderTest, TestOneClockwiseLeft) {
isLeftHand = true;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
setAndRead(0, false);
setAndRead(1, false);
setAndRead(0, true);
setAndRead(1, true);

EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 0);
EXPECT_EQ(updates[0].clockwise, true);
}

TEST_F(EncoderTest, TestOneClockwiseRightSent) {
isLeftHand = false;
encoder_init();
// send 4 pulses. with resolution 4, that's one step and we should get 1 update.
setAndRead(2, false);
setAndRead(3, false);
setAndRead(2, true);
setAndRead(3, true);

uint8_t slave_state[2] = {0};
encoder_state_raw(slave_state);

EXPECT_EQ((int8_t)slave_state[0], -1);
}

/* this test will not work after the previous test.
* this is due to encoder_value[1] already being set to -1 when simulating the right half.
* When we now receive this update acting as the left half, there is no change.
* This is hard to mock, as the static values inside encoder.c normally exist twice, once on each half,
* but here, they only exist once.
*/

// TEST_F(EncoderTest, TestOneClockwiseRightReceived) {
// isLeftHand = true;
// encoder_init();

// uint8_t slave_state[2] = {255, 0};
// encoder_update_raw(slave_state);

// EXPECT_EQ(uidx, 1);
// EXPECT_EQ(updates[0].index, 1);
// EXPECT_EQ(updates[0].clockwise, true);
// }

TEST_F(EncoderTest, TestOneCounterClockwiseRightReceived) {
isLeftHand = true;
encoder_init();

uint8_t slave_state[2] = {0, 0};
encoder_update_raw(slave_state);

EXPECT_EQ(uidx, 1);
EXPECT_EQ(updates[0].index, 1);
EXPECT_EQ(updates[0].clockwise, false);
}
34 changes: 34 additions & 0 deletions quantum/encoder/tests/mock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright 2021 Balz Guenat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "mock.h"

bool pins[32] = {0};
bool pinIsInputHigh[32] = {0};

uint8_t mockSetPinInputHigh(pin_t pin) {
// dprintf("Setting pin %d input high.", pin);
pins[pin] = true;
pinIsInputHigh[pin] = true;
return 0;
}

bool mockReadPin(pin_t pin) { return pins[pin]; }

bool setPin(pin_t pin, bool val) {
pins[pin] = val;
return val;
}
40 changes: 40 additions & 0 deletions quantum/encoder/tests/mock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Copyright 2021 Balz Guenat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <stdint.h>
#include <stdbool.h>

/* Here, "pins" from 0 to 31 are allowed. */
#define ENCODERS_PAD_A \
{ 0 }
#define ENCODERS_PAD_B \
{ 1 }

typedef uint8_t pin_t;

extern bool pins[];
extern bool pinIsInputHigh[];

#define setPinInputHigh(pin) (mockSetPinInputHigh(pin))
#define readPin(pin) (mockReadPin(pin))

uint8_t mockSetPinInputHigh(pin_t pin);

bool mockReadPin(pin_t pin);

bool setPin(pin_t pin, bool val);
Loading

0 comments on commit b3fc33f

Please sign in to comment.