summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILDING.md24
-rw-r--r--TESTING.md28
-rw-r--r--src/drivers/include/drivers/adc.hpp4
-rw-r--r--src/drivers/test/CMakeLists.txt2
-rw-r--r--src/drivers/test/test_adc.cpp2
-rw-r--r--src/drivers/test/test_samd.cpp32
-rw-r--r--src/tangara/test/CMakeLists.txt7
-rw-r--r--src/tangara/test/battery/test_battery.cpp67
-rw-r--r--test/CMakeLists.txt2
9 files changed, 141 insertions, 27 deletions
diff --git a/BUILDING.md b/BUILDING.md
index 094c1551..571aa359 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -1,9 +1,3 @@
-<!--
-Copyright 2023 jacqueline <me@jacqueline.id.au>
-
-SPDX-License-Identifier: CC0-1.0
--->
-
# Building and flashing
1. Make sure you've got all of the submodules in this repo correctly initialised:
@@ -34,28 +28,14 @@ There is also a `.env.fish` for fish users.
onto your board, something like:
```
-idf.py -p /dev/ttyUSB0 -b 1000000 flash
+idf.py -p /dev/serial/by-id/usb-cool_tech_zone_Tangara_* -b 1000000 flash
```
(give or take the correct serial port)
# Running tests
-(Note: tests are currently broken, and have been for a while. Sorry! IOU a working test suite by the time we ship devices :))
-
-Tests are implemented as a separate application build, located in the `test`
-directory. We use Catch2 as our test framework.
-
-To run them, navigate to the test directory, then build and flash as normal.
-Connect to your device via UART, and you will be presented with a terminal
-prompt that you may run tests from.
-
-To add new tests to a components, you must:
- 1. Create a `test` subcomponent within that component. See `drivers/test` for
- an example of this.
- 2. Include the component in the test build and list of testable components, in
- `test/CMakeLists.txt`.
-
+See `TESTING.md` for an overview of how to write and run our on-device test suite.
# VSCode setup
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 00000000..3776c239
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,28 @@
+# Running tests
+
+Our test suite currently must be run on an actual device. A subset of our tests may run correctly on a bare ESP32-WROVER module, but in general they do rely on the real Tangara hardware being available.
+
+Tests are implemented as a separate application build, located in the `test`
+directory. We use Catch2 as our test framework.
+
+To run them, navigate to the test directory, then build and flash as normal. e.g.
+
+```
+idf.py -p /dev/serial/by-id/usb-cool_tech_zone_Tangara_* app-flash
+```
+
+Connect to your device via serial, and you will be presented with
+ variant of our standard dev console. To run all tests, simply execute `catch` in the console.
+
+The `catch` command accepts additional arguments as if it were a standard Catch2 test runner binary. You can therefore see a brief guide to the available options with `catch -?`.
+
+# Writing tests
+
+Tests live within the `test` subcomponent of the component that the tests are written for. In practice, this means that device driver tests should live in `src/drivers/test`, whilst most other tests live in `src/tangara/test`.
+
+## Tags
+
+Catch2 has a flexible system of test tags that can be used to categorise different test cases. Feel free to add new tags as-needed. In general, most tests should be tagged with one of:
+
+- `[integration]`, for tests that rely on the hardware being in a specific state
+- `[unit]`, for tests that operate purely in-memory, either without any additional device drivers needed, or by using test doubles rather than real drivers.
diff --git a/src/drivers/include/drivers/adc.hpp b/src/drivers/include/drivers/adc.hpp
index 3e94a9ee..2fd8a626 100644
--- a/src/drivers/include/drivers/adc.hpp
+++ b/src/drivers/include/drivers/adc.hpp
@@ -22,12 +22,12 @@ class AdcBattery {
public:
static auto Create() -> AdcBattery* { return new AdcBattery(); }
AdcBattery();
- ~AdcBattery();
+ virtual ~AdcBattery();
/**
* Returns the current battery level in millivolts.
*/
- auto Millivolts() -> uint32_t;
+ virtual auto Millivolts() -> uint32_t;
private:
adc_oneshot_unit_handle_t adc_handle_;
diff --git a/src/drivers/test/CMakeLists.txt b/src/drivers/test/CMakeLists.txt
index ff1dab0b..f18dc357 100644
--- a/src/drivers/test/CMakeLists.txt
+++ b/src/drivers/test/CMakeLists.txt
@@ -3,5 +3,5 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "test_adc.cpp" "test_storage.cpp" "test_dac.cpp"
+ SRCS "test_adc.cpp" "test_storage.cpp" "test_dac.cpp" "test_samd.cpp"
INCLUDE_DIRS "." REQUIRES catch2 cmock drivers fixtures)
diff --git a/src/drivers/test/test_adc.cpp b/src/drivers/test/test_adc.cpp
index df103af3..a8dad4bd 100644
--- a/src/drivers/test/test_adc.cpp
+++ b/src/drivers/test/test_adc.cpp
@@ -12,7 +12,7 @@
namespace drivers {
-TEST_CASE("battery measurement", "[integration]") {
+TEST_CASE("battery adc", "[integration]") {
AdcBattery battery;
SECTION("voltage is within range") {
diff --git a/src/drivers/test/test_samd.cpp b/src/drivers/test/test_samd.cpp
new file mode 100644
index 00000000..c466d88e
--- /dev/null
+++ b/src/drivers/test/test_samd.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "drivers/samd.hpp"
+
+#include <cstdint>
+
+#include "catch2/catch.hpp"
+
+#include "i2c_fixture.hpp"
+
+namespace drivers {
+
+TEST_CASE("samd21 interface", "[integration]") {
+ I2CFixture i2c;
+ auto samd = std::make_unique<Samd>();
+
+ REQUIRE(samd);
+
+ SECTION("usb reports connection") {
+ samd->UpdateUsbStatus();
+
+ auto status = samd->GetUsbStatus();
+
+ REQUIRE(status == Samd::UsbStatus::kAttachedIdle);
+ }
+}
+
+} // namespace drivers
diff --git a/src/tangara/test/CMakeLists.txt b/src/tangara/test/CMakeLists.txt
new file mode 100644
index 00000000..728c06b0
--- /dev/null
+++ b/src/tangara/test/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright 2023 jacqueline <me@jacqueline.id.au>
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+idf_component_register(
+ SRC_DIRS "battery"
+ INCLUDE_DIRS "." REQUIRES catch2 cmock tangara fixtures)
diff --git a/src/tangara/test/battery/test_battery.cpp b/src/tangara/test/battery/test_battery.cpp
new file mode 100644
index 00000000..7b55bd59
--- /dev/null
+++ b/src/tangara/test/battery/test_battery.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2024 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "battery/battery.hpp"
+
+#include <cstdint>
+#include <memory>
+
+#include "catch2/catch.hpp"
+#include "drivers/adc.hpp"
+#include "i2c_fixture.hpp"
+
+namespace battery {
+
+class FakeAdc : public drivers::AdcBattery {
+ private:
+ uint32_t mv_;
+
+ public:
+ virtual auto Millivolts() -> uint32_t override { return mv_; }
+ auto Millivolts(uint32_t mv) -> void { mv_ = mv; }
+};
+
+TEST_CASE("battery charge state", "[unit]") {
+ I2CFixture i2c;
+
+ // FIXME: mock the SAMD21 as well.
+ std::unique_ptr<drivers::Samd> samd{drivers::Samd::Create()};
+ FakeAdc* adc = new FakeAdc{}; // Freed by Battery.
+ Battery battery{*samd, std::unique_ptr<drivers::AdcBattery>{adc}};
+
+ SECTION("full charge is 100%") {
+ // NOTE: in practice, our curve-fitting slightly undershoots
+ adc->Millivolts(4210);
+
+ battery.Update();
+
+ auto state = battery.State();
+ REQUIRE(state.has_value());
+ REQUIRE(state->percent == 100);
+ }
+
+ SECTION("empty charge is 0%") {
+ adc->Millivolts(3000);
+
+ battery.Update();
+
+ auto state = battery.State();
+ REQUIRE(state.has_value());
+ REQUIRE(state->percent == 0);
+ }
+
+ SECTION("overcharge is clamped to 100%") {
+ adc->Millivolts(5000);
+
+ battery.Update();
+
+ auto state = battery.State();
+ REQUIRE(state.has_value());
+ REQUIRE(state->percent == 100);
+ }
+}
+
+} // namespace battery
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 072a350f..ee553498 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -27,6 +27,6 @@ list(APPEND EXTRA_COMPONENT_DIRS
)
# List all components that include tests here.
-set(TEST_COMPONENTS "drivers")
+set(TEST_COMPONENTS "drivers" "tangara")
project(device_tests)