Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,42 @@ on:
branches: [main]
workflow_dispatch:
jobs:
test-c_cpp:
runs-on: ubuntu-24.04-arm
steps:
- name: check out repository
uses: actions/checkout@v4
with:
submodules: 'recursive'

- name: ensure build directory exists
# this is needed so that the cache action can do the caching
run: mkdir -p build

- name: cache waf build directory
uses: actions/cache@v4
with:
path: build
# create a cache key based on the wscript files
key: ${{ runner.os }}-waf-build-${{ hashFiles('**/wscript') }}
restore-keys: |
${{ runner.os }}-waf-build-

- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Pre-build dev container image and run tests inside dev container
uses: devcontainers/[email protected]
with:
imageName: ghcr.io/monome/norns-ci
cacheFrom: ghcr.io/monome/norns-ci
push: never
runCmd: ./waf configure && sh ./test.sh

test-lua:
runs-on: ubuntu-latest
steps:
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
[submodule "third-party/doctest"]
path = third-party/doctest
url = https://github.com/doctest/doctest.git
[submodule "third-party/link"]
path = third-party/link
url = https://github.com/Ableton/link.git
[submodule "third-party/trompeloeil"]
path = third-party/trompeloeil
url = https://github.com/rollbear/trompeloeil.git
[submodule "crone/softcut"]
path = crone/softcut
url = https://github.com/monome/softcut-lib.git
Expand Down
57 changes: 57 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,61 @@ api docs for main
to view the api docs for the `main` branch,
visit https://monome.org/docs/norns/api.

testing c/c++ code
------------------

### quick start

run all tests:
```bash
./test.sh
```

run specific test:
```bash
# example: run matron `clock.h` tests
./test.sh --targets=test_matron_clock
```

see [tests/README.md](tests/README.md) for infrastructure details, advanced patterns, and comprehensive examples.

### writing your first test

tests mirror source structure. create `test_*.cpp` files, and they get picked up by the test runner automatically:

```
tests/matron/test_args.cpp → matron/src/args.c
tests/crone/test_window.cpp → crone/src/Window.cpp
```

**test C code:**

```cpp
#include <doctest/doctest.h>

extern "C" {
#include "args.h"
}

TEST_CASE("args_parse handles local port") {
char *argv[] = {"matron", "-l", "8888", nullptr};
args_parse(3, argv);
CHECK(std::string(args_local_port()) == "8888");
}
```

**test C++ code:**

```cpp
#include <doctest/doctest.h>
#include "Window.h"

TEST_CASE("window starts at zero") {
CHECK(Window::raisedCosShort[0] == doctest::Approx(0.0f));
}
```

**assertions:**
- `CHECK(expr)` — non-fatal
- `REQUIRE(expr)` — fatal, stops test
- `CHECK(value == doctest::Approx(expected))` — floating point
1 change: 1 addition & 0 deletions clang-format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ find matron/src -regex .*[\.][ch] | xargs clang-format -i
find maiden-repl/src -regex .*[\.][ch] | xargs clang-format -i
find crone/src -type f \( -name '*.c' -o -name '*.h' -o -name '*.cpp' \) | xargs clang-format -i
find watcher/src -regex .*[\.][ch] | xargs clang-format -i
find tests -type f \( -name '*.c' -o -name '*.h' -o -name '*.cpp' -o -name '*.hpp' \) | xargs clang-format -i
2 changes: 2 additions & 0 deletions crone/src/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

using namespace crone;

constexpr size_t Window::raisedCosShortLen;

const float Window::raisedCosShort[Window::raisedCosShortLen] = {
#include "cos_win.h"
};
17 changes: 13 additions & 4 deletions matron/src/args.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,29 @@ int args_parse(int argc, char **argv) {
while ((opt = getopt(argc, argv, "o:e:l:c:f:h")) != -1) {
switch (opt) {
case 'l':
strncpy(a.loc_port, optarg, ARG_BUF_SIZE - 1);
snprintf(a.loc_port, ARG_BUF_SIZE, "%s", optarg);
break;
case 'e':
strncpy(a.ext_port, optarg, ARG_BUF_SIZE - 1);
snprintf(a.ext_port, ARG_BUF_SIZE, "%s", optarg);
break;
case 'o':
strncpy(a.remote_port, optarg, ARG_BUF_SIZE - 1);
snprintf(a.remote_port, ARG_BUF_SIZE, "%s", optarg);
break;
case 'c':
strncpy(a.crone_port, optarg, ARG_BUF_SIZE - 1);
snprintf(a.crone_port, ARG_BUF_SIZE, "%s", optarg);
break;
case 'f':
snprintf(a.framebuffer, ARG_BUF_SIZE, "%s", optarg);
break;
case '?':
case 'h':
default:
fprintf(stdout, "Start matron with optional overrides:\n");
fprintf(stdout, "-l override OSC local port [default %s]\n", a.loc_port);
fprintf(stdout, "-e override OSC ext port [default %s]\n", a.ext_port);
fprintf(stdout, "-o override OSC remote port [default %s]\n", a.remote_port);
fprintf(stdout, "-c override crone port [default %s]\n", a.crone_port);
fprintf(stdout, "-f override framebuffer path [default %s]\n", a.framebuffer);
exit(1);
;
}
Expand All @@ -66,3 +71,7 @@ const char *args_remote_port(void) {
const char *args_crone_port(void) {
return a.crone_port;
}

const char *args_framebuffer_path(void) {
return a.framebuffer;
}
2 changes: 1 addition & 1 deletion matron/src/args.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ extern const char *args_local_port(void);
extern const char *args_ext_port(void);
extern const char *args_remote_port(void);
extern const char *args_crone_port(void);
extern const char *args_monome_path(void);
extern const char *args_framebuffer_path(void);
25 changes: 23 additions & 2 deletions matron/src/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "jack_client.h"

static clock_source_t clock_source;
static bool clock_source_initialized = false;

void clock_init() {
clock_set_source(CLOCK_SOURCE_INTERNAL);
Expand Down Expand Up @@ -132,9 +133,29 @@ void clock_reschedule_sync_events_from_source(clock_source_t source) {
}

void clock_set_source(clock_source_t source) {
if (clock_source != source && source == CLOCK_SOURCE_LINK) {
// first call from clock_init establishes the default source.
// always reschedule on first set to bootstrap scheduler state.
if (!clock_source_initialized) {
clock_source_initialized = true;
if (source == CLOCK_SOURCE_LINK) {
clock_link_join_session();
}
clock_source = source;
clock_scheduler_reschedule_sync_events();
return;
}

// no-op when source is already active. avoids duplicate reschedules
// and unnecessary link session join/leave churn.
if (clock_source == source) {
return;
}

// join link session when switching to link, leave when switching away.
// only performed when crossing the link boundary to avoid redundant calls.
if (source == CLOCK_SOURCE_LINK) {
clock_link_join_session();
} else if (clock_source != source && clock_source == CLOCK_SOURCE_LINK) {
} else if (clock_source == CLOCK_SOURCE_LINK) {
clock_link_leave_session();
}

Expand Down
2 changes: 2 additions & 0 deletions matron/src/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

typedef enum {
CLOCK_SOURCE_INTERNAL = 0,
Expand Down Expand Up @@ -31,3 +32,4 @@ void clock_set_source(clock_source_t source);
double clock_get_beats();
double clock_get_system_time();
double clock_get_tempo();
uint64_t clock_number_of_link_peers();
Loading