---
name: snip
description: "Write snip tests (copy-paste unit tests) for C modules in this project"
argument-hint: "<module-path> [name]"
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
  - Glob
  - Grep
---

<objective>
Write a snip test for a C module. Snip tests are self-contained, copy-paste unit tests that compile a module inline (without a build system) using stub headers.

A snip test consists of two files:
- `<name>.c.snip` — the test source, processed by `sniprun` into a `.c` file then compiled
- `<name>.c.make` — a bash script that compiles and runs the test

Run with: `sniprun <name>.c.snip`

sniprun generates `<name>.c` compiles it, runs it, and deletes it. 

IMPORTANT: when the test fails the generate `.c` file is not deleted and can be viewed to see if replacements worked as expected
</objective>


<process>

## Step 1 — Read the module source

Read the module `.h` and `.c` files to understand:
- What functions/types to test
- Which SNIP tag delimits the testable code (the `//SNIP_tag` markers in the source)
- Which functions the module calls (needed to check stub coverage)

The SNIP tags in source files look like:
```c
//SNIP_flow_module     ← opening marker (same string used as closing)
... testable code ...
//SNIP_flow_module     ← closing marker
```

`snipcat TAG FILE` extracts everything between the two lines matching TAG.


## Step 2 — Check stub coverage in include/

The stubs live in `test/include/`. Check whether the module's calls are already stubbed:
If a needed field or function is missing, add it to the appropriate stub header before writing the test. 
Keep stubs minimal.

## Step 3 — Write the .c.snip file

### Template structure

```c
#include <stdio.h>
#include <string.h>

#include "asserts.h"

//SNIP_FILE SNIP_tag_name ../../src/nx_foo_module.h
//SNIP_FILE SNIP_tag_name ../../src/nx_foo_module.c

/* test helpers */

int main(int argc, char *argv[])
{
    /* tests */
    print_results(argv[0]);
    return 0;
}
```

- `//SNIP_FILE TAG PATH` inlines the snip-tagged section of PATH into the generated `.c` file
- The TAG in the directive must exactly match the tag string in the source file
- Both `.h` and `.c` of the module are inlined using `//SNIP_FILE` — include the header first

## Step 4 — Write the .c.make file

```bash
#!/bin/bash
set -euo pipefail

cd $(dirname $0)

snip_test=<name>

musl-gcc -Wall -Werror -Wno-unused-function -Wno-sign-compare -g -O0 \
    $snip_test.c \
    -o $snip_test \
    -lm \
    && ./$snip_test \
    && rm -f ./$snip_test ./${snip_test}.c
```

Make it executable: `chmod +x <name>.c.make`


## Step 5 — Run and iterate

```bash
sniprun <name>.c.snip
```

`sniprun` generates `<name>.c` next to the `.c.snip`, compiles it, runs it, then the make script deletes both the binary and the `.c` file on success.

## Step 6 — Source bugs found while writing tests

When writing the test forces compilation of the module under `-Wall -Werror`, it commonly surfaces bugs the build system would have hidden. Fix them in the source.

</process>
