[RFC]: Extend stdlib's doctesting approach to C examples
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 28/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- c, javascript, node.js
- Área
- build-system, testing-qa, tooling
Línea de trabajo
Comienza leyendo los objetivos de doctest existentes en tools/make/lib/doctest/c/doctest-c.mk y las issues relacionadas #G96 y #1378. Revisa los límites propuestos de extracción, instrumentación, compilación, ejecución y comparación, y resuelve después las cuestiones sobre la ruta de inclusión, el helper estático, la nomenclatura y las reglas de omisión antes de la implementación; se considera terminado cuando haya un diseño acordado para el pipeline de doctesting de C.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
This RFC proposes a suite of packages under @stdlib/_tools/doctest/c implementing an automated extract → instrument → compile → run → compare pipeline for testing C code examples embedded in src/*.c source files and README.md files.
Proposed Changes
Package layout
@stdlib/_tools/doctest/c/ ← orchestrator (bin/cli)
├── extract/
├── instrument/
├── compile/
├── run/
└── compare/
Make targets follow the existing doctest namespace in tools/make/lib/doctest/c/doctest-c.mk.
Sub-package API
@stdlib/_tools/doctest/c/extract
extract( filePath, mode ) → Array<block>
// filePath: string — absolute path to a .c source file or README.md
// mode: 'src' | 'markdown'
// returns an array of self-contained block objects, one per testable example
/* block = {
file: string,
blockIndex: number, ← 0-based, helps segregating example blocks from same file
includes: Array<{ text: string, line: number }>, ← #include lines hoisted for this block
staticHelpers: Array<{ text: string, line: number }>, ← array of hoisted internal static functions called by this block
fileScope: Array<{ text: string, line: number }>, ← pre-function declarations + function definitions for this block (to be hoisted outside main()) (ex, @stdlib/ndarray/base/function-object)
body: Array<{ text: string, line: number }>, ← procedural lines for main() for this block
annotations: Array<{ text: string, line: number }> ← extracted annotation values (e.g., "~1.571", "true") from // returns comments
}
*/
Parses @example Doxygen blocks (src mode) or ```c ``` fenced blocks (markdown mode). Each block is independent.
Note: Contiguous lines are grouped into a single text block. The line property indicates the starting line number of that contiguous block
@stdlib/_tools/doctest/c/instrument
instrument( block ) → { tmpFile, annotations }
// block: block object from extract()
// tmpFile: absolute path to the generated .c file written to os.tmpdir()
// annotations: Array<{ annotation, type, varName, file, line }>
Wraps the block into a compilable .c file: injects necessary stdlib and standard library headers, hoists static helpers and file-scope declarations, wraps procedural code in main(), and emits a type-aware printf per // returns annotation. Injects #line N "original/file.c" directives so all compiler errors reference the original file and line, not the generated tmp file.
For each annotation, type inference runs via a inferType helper that backward-scans the body lines accumulated up to that annotation to find the preceding variable declaration.
@stdlib/_tools/doctest/c/compile
compile( tmpFile ) → { ok, binary, stderr }
// tmpFile: path from instrument()
// binary: path to the compiled executable (in os.tmpdir())
// stderr: raw compiler output (already line-mapped to original file via #line)
Resolves include paths via manifest.json using @stdlib/utils/library-manifest. Handles supplemental headers referenced inside a snippet but absent from the package's core manifest dependencies.
@stdlib/_tools/doctest/c/run
run( binary, opts ) → { ok, stdout, stderr, timedOut }
// binary: path from compile()
// opts: { timeout: number } — default 15000 ms
Executes the compiled binary via spawnSync with a configurable timeout.
@stdlib/_tools/doctest/c/compare
compare( stdout, annotations ) → Array<{ pass, got, expected, file, line }>
// stdout: raw stdout string from run()
// annotations: annotation metadata array from instrument()
Normalizes tokens (inf/-inf → ±Infinity, nan → NaN, trailing f stripped) before comparison. Uses Object.is for -0 detection and delegates ~-prefixed approximate values to @stdlib/_tools/doctest/compare-values and direct comparison for ints and bools.
Block Skip Rules
In src/*.c files, a trailing comment on the function definition opts the @example blocks of that function out:
// Skips @example blocks of that function:
static double foo( double x ) { // stdlib-c-doctest disable
...
}
// Skip all remaining @example blocks in the file:
// stdlib-c-doctest disable-file
In README.md files, the existing <!-- run-disable --> comment before a fenced block opts it out. napi packages (paths containing /napi/) are excluded automatically by the orchestrator.
CLI
Invoked by make targets and pre-commit hooks, one file at a time:
node lib/node_modules/@stdlib/_tools/doctest/c/bin/cli.js \
--mode=src \
--file=lib/node_modules/@stdlib/math/base/special/sin/src/main.c \
[--verbose] [--timeout=<ms>]
| Flag | Description |
|---|---|
--mode |
src or markdown |
--file |
File to process |
--verbose |
Print compiler output and instrumentation trace |
--timeout |
Per-binary execution timeout in ms (default: 15000) |
Output Format
Compiler errors are surfaced directly from the compiler's own output, which are already mapped to the original file via #line directives. Annotation mismatches and pipeline errors (compare stage) are formatted by the orchestrator as file:line:col: error: message [rule].
Stretch Goals
- Mutated scalar annotation:
// out => 0.5 - Flat array annotation:
// x => <double>[ 1.0, 2.0, 3.0 ] - Complex number annotation:
// returns <complex128>[re, im]
Related Issues
Related issues #G96 , #1378.
Questions
-
Include path resolution: Should supplemental dep resolution remain in the doctest tool, or should a
docstask config be added tomanifest.jsonsolibrary-manifesthandles it fully? -
Static helper handling: Should internal
statichelpers be hoisted exactly into the tmp file, or promoted to namespaced internal symbols (e.g.,stdlib_internal_*) via a restricted header? -
Tool structuring/naming: Any feedback on the sub-package naming or placement under
@stdlib/_tools/doctest/c/? -
Skip rule scope for
@exampleblocks: When// stdlib-c-doctest disableis placed on a function definition, it skips all@exampleblocks for that function. However, since a function can have multiple example blocks, should there be a way to skip specific blocks (e.g., using an index-based approach)?
Other
No.
Checklist
- I have read and understood the Code of Conduct.
- Searched for existing issues and pull requests.
- The issue name begins with
RFC:.
- Lenguaje dominante
- JavaScript
- Estrellas
- 6k
- Forks
- 1.3k
- Merge medio
- 1 d 10 h
- PR fusionados (30 d)
- 568
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de stdlib-js/stdlib
-
Fix JavaScript lint errorsPosiblemente ocupada @lb1192176991-lab la tomó hace 3 días. AbiertoGood First Issue
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
stdlib-js/stdlib#15831 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
`@stdlib/string/base/percent-encode` produces malformed encoding and silently drops charactersPosiblemente ocupada @barbierajput378-pixel la tomó hace 8 días. AbiertoBug
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
stdlib-js/stdlib#15595 · 6 comentarios ·
Los mantenedores suelen responder en 1 día
-
[Bug]: kumaraswamy/kurtosis returns non-excess kurtosis (missing −3)Posiblemente ocupada @Planeshifter la tomó hace 8 días. AbiertoBug Statistics
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
stdlib-js/stdlib#15461 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
[Bug]: rayleigh/mgf returns wrong values due to misplaced parenthesisPosiblemente ocupada @anandkaranubc la tomó hace 11 días. AbiertoBug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
stdlib-js/stdlib#15456 · 6 comentarios · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
@stdlib/array/fixed-endian-factory allows misaligned byte offsets and fractional lengthsPosiblemente ocupada @kanikasharma-18 la tomó hace 23 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
stdlib-js/stdlib#15193 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de stdlib-js/stdlib
Issues similares
-
Dificultad 2/5 Menos de una hora Aptitud para principiantes 85/100
capricorn86/happy-dom#2474 ·
Los mantenedores suelen responder en 2 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 90/100
juice-shop/juice-shop#3662 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
-
Add unit-test coverage for API URL resolution and device authentication error handlingPosiblemente ocupada @Simranjit8933 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 90/100
fossasia/eventyay-checkin#170 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día