# The suite

The `tests/testthat/` layout, its helpers,
and running the whole suite or any part of it.

```sh
R -q -e 'testthat::test_local()'                          # everything
R -q -e "testthat::test_local(filter = '^array$')"        # one file
R -q -e "testthat::test_local(filter = 'arrow')"          # every arrow file
R -q -e "testthat::test_local(filter = '^(array|bind)$')" # exactly these two
```

`filter` is a **regular expression**, matched against each file name with
`test-` and `.R` stripped — so a family is a substring,
several named files are an alternation,
and one file is anchored to keep it from matching its neighbours.

`test_local()` runs directly and unconditionally,
without reading `tests/testthat.R`.
With the fast path set up
([`build/fast-paths/`](/handbook/build/fast-paths/README.md))
the edit-test loop stays in the seconds range.

**The layout.**
Tests are flat files `test-<topic>.R`,
named for the `R/` file they cover,
the DuckDB feature they round-trip,
or a shared prefix for multi-pass areas;
the file name is the unit of selection.
Beside them: `helper-*.R` and `setup.R`,
then `data/` (Parquet fixtures, reached via `test_path()` or as bare
relative paths inside SQL),
and `_snaps/`
([`snapshots/`](/handbook/testing/snapshots/README.md)).

**The helpers.**
Every `helper-*.R` is sourced before the first test,
and that set is the list.
Each should open with a header saying why it exists;
`helper-DBItest.R` and `helper-skip.R` do not yet.
Three constraints are not obvious from reading one:
`helper-DBItest.R`'s `make_context()` call must stay in the helper,
any expectation whose output can carry the package name goes
through `transform_package_name` from `helper-snapshot.R`,
and two paths that should name the same directory are compared
with `expect_same_path` from `helper-storage.R` —
on Windows `dirname()` returns `/` separators while `file.path()`
and `tempdir()` keep the `\` they were handed,
so `expect_equal()` reports a difference that is not there.
`local_con()`, the self-disconnecting connection fixture,
is package code (`R/test-fixtures.R`);
the suite runs with the namespace loaded,
so internal functions — `get_package_name()` among them —
are callable unqualified.
Always ask for the package name rather than writing it
([`branches/flavors/`](/handbook/branches/flavors/README.md)).

**A platform gap is a canary, not a skip.**
`test-duckdb-extensions.R` installs a real extension,
so it branches on whether DuckDB publishes one for the platform
running it — `extensions_published()`, package code in `R/extensions.R`,
over the engine's own `PRAGMA platform`
([`usage/extensions/`](/handbook/usage/extensions/README.md)
owns which platforms those are).
Where the repository carries nothing,
the test asserts the download error rather than skipping,
so the day the gap closes it is the assertion that fails,
on the platform itself.
A skip would have gone on passing silently.
