ASkeleTon
Generate C/C++ unit test scaffolding from compile_commands.json with GoogleTest, Boost.Test, or Catch2.
Outputs fixtures, tests, Makefiles, and .cfg data files with deterministic or rule-based values.
Highlights
- AST-driven discovery of functions, methods, and constructors.
- Profiles for data generation:
random,boundary,safe,stress. - Coverage policies:
strict,balanced,aggressive. - Rule-based values extracted from comparisons.
- Structured skip reasons in reports (
abstract_record,missing_instance_strategy, etc.). - Structured input support for
std::optional,std::pair, andstd::tuple. - JSON report with per-target summary.
- Output inside the SUT repo by default.
- Clean, structured console output with optional JSON execution log.
Quick Start
ASKELETON_HOME=$(pwd) ./askeleton --bootstrap-compdb -p examples examples/sut.cppBy default, ASkeleTon generates GoogleTest scaffolding and writes output under
tests/generated relative to the first source file passed on the command line.
Install (Ubuntu) ASkeleTon requires LLVM/Clang 18, libclang development headers, and a C/C++ build toolchain.
On Ubuntu 24.04, these packages are available directly from the default repositories. On Ubuntu 22.04, install LLVM/Clang 18 from the official LLVM APT repository first: https://apt.llvm.org/
Then install:
sudo apt update
sudo apt install -y clang-18 llvm-18 llvm-18-dev llvm-18-tools libclang-18-dev build-essentialGoogleTest (libgtest-dev) is required for the main reproducibility workflow.
Boost.Test and Catch2 are optional backend dependencies; they are only
required when generating, building, or running scaffolding for those
backends.
Install GoogleTest for the default setup and the minimal end-to-end reproducibility workflow:
sudo apt install -y libgtest-devIf you want to generate tests for Boost.Test or Catch2, install the corresponding optional backend libraries:
sudo apt install -y libboost-dev catch2To install support for all available frameworks:
sudo apt install -y libboost-dev libgtest-dev catch2Other distros Install equivalents of LLVM/Clang 18, libclang development headers, and a C/C++ build toolchain.
Build
make CXX=clang++-18
./askeleton --versionsystem_files.json is created automatically if missing. Use
--no-system-files-refresh to skip this check.
Minimal End-to-End Reproducibility Workflow For a compact end-to-end workflow aligned with the paper's generate-build-run-refine path, run:
./scripts/check_main_workflow.shThis script performs a minimal examples/sut.cpp workflow aligned with that
usage path:
- bootstrap
compile_commands.json - generate GoogleTest scaffolding plus
.cfgdata - build the generated test
- execute the generated binary
- edit
sut.cfgand confirm the rerun changes behavior - emit
report.jsonandlog.json
The manuscript walkthrough example itself uses examples/sut_showcase.cpp; the
script above is the smaller reproducibility check intended for clean clones.
To inspect the generated files yourself, pass an explicit output directory:
./scripts/check_main_workflow.sh /tmp/askeleton_main_workflowUsage
askeleton [options] <source0> [... <sourceN>]
Use --out-dir to override the default output location.
Key options:
-p <build-path>: path tocompile_commands.json.--bootstrap-compdb: auto-create/append minimal compile commands for missing source entries.--framework=<gtest|boost|catch>: select test framework.--profile=<random|boundary|safe|stress>: data generation profile.--coverage-mode=<strict|balanced|aggressive>: generation coverage policy.--oracle-mode=<mirror|explicit|property>: expected-value strategy.--seed=<N>: deterministic data generation.--rule-data: explicitly enable the default AST-guided rule-based values.--no-rule-data: disable AST-guided rule-based values and use fallback-only data generation.--rule-max-cases=<N>: limit rule-based test cases per function.--out-dir=<path>: output directory for generated tests.--include-impl-under-include: allow compiling.c/.cc/.cppunderinclude/.--report=<path>: write a JSON report of generated/skipped tests.--report-json: write a JSON report to<out-dir>/askeleton_report.json.--log-json=<path>: write an execution log with summary/warnings.--no-system-files-refresh: do not auto-createdata/system_files.jsonif missing.--quiet,--verbose,--debug: control console verbosity.--extra-arg,--extra-arg-before: pass extra compiler args to Clang tooling.
For exhaustive option semantics and examples, see:
Console Output By default you get a concise progress view plus a final summary. Use:
--quietto print only errors.--verboseto include per-entity progress.--debugto include detailed parameter/return signatures.
To collect a JSON execution log with inputs, counts, warnings, and timings,
use --log-json=<path>.
Generated Makefiles Generated Makefiles follow a consistent structure across frameworks:
- C/C++ split compilation:
.cdependencies useCC, test translation units useCXX. - Extra flags/libraries are overridable without editing templates:
EXTRA_CPPFLAGS,EXTRA_CFLAGS,EXTRA_CXXFLAGSEXTRA_LDFLAGS,EXTRA_LIBS
- Base link libraries are exposed as
LIBSin all framework Makefiles. - Standard targets are available in all frameworks:
all,test,clean,compilation.
Example:
make EXTRA_LIBS="-lcrypto" EXTRA_LDFLAGS="-L/path/to/lib"Data Generation These examples cover the most common ways to adjust generation behavior:
Default generation:
ASKELETON_HOME=$(pwd) ./askeleton --bootstrap-compdb -p examples examples/sut.cppDeterministic generation:
ASKELETON_HOME=$(pwd) ./askeleton --bootstrap-compdb --seed=123 -p examples examples/sut.cppBoundary-focused inputs:
ASKELETON_HOME=$(pwd) ./askeleton --bootstrap-compdb --profile=boundary -p examples examples/sut.cppConservative generation policy:
ASKELETON_HOME=$(pwd) ./askeleton --bootstrap-compdb --coverage-mode=strict -p examples examples/sut.cppFor more option combinations, see doc/CLI.md.
Coverage Modes
Coverage mode controls how selective ASkeleTon is when deciding whether to
generate a test for a callable. This is separate from the data-generation
--profile.
balanced: default behavior and the recommended starting point.strict: favors conservative, easy-to-review scaffolding and skips callables that require mutable pointer/reference handling or non-default instance construction.aggressive: accepted for compatibility and experimentation; currently close tobalanced, but kept explicit so repository workflows and paper tables can reference it directly.
If a callable is skipped, check the report for the recorded reason.
Expected Value Strategy ASkeleTon supports three oracle modes:
explicit: default behavior. Generated tests first look forexpectedin the.cfg; if no override is present, they fall back to a mirrored execution.mirror: generated tests deriveexpectedfrom a second isolated execution of the same callable with the same case data.property: generated tests replay the same callable with isolated inputs and compare the observable result across both executions.
In practice, the .cfg file stores the editable case data, and explicit
lets users override expected values when needed. These modes help keep
generated scaffolding stable and reproducible, but they are not an independent
semantic oracle for the SUT.
Type Factories and Stubs
Use data/type_factories.json to customize how complex types are initialized
in generated fixtures and tests.
For the configuration format, supported strategies, and examples, see
doc/TypeFactories.md.
Instance Resolution
For non-static methods, ASkeleTon tries to resolve a usable instance
automatically. When the AST cannot infer a safe construction path, configure
data/instance_strategies.json.
For the full resolution order, configuration format, and examples, see
doc/InstanceStrategies.md.
Supported Structured Inputs
ASkeleTon supports structured input for some common C++ standard library
shapes in generated .cfg files and fixtures:
std::optional<T>std::pair<T, U>std::tuple<Ts...>
These are stored in the .cfg as structured keys rather than flattened strings.
Examples:
value.has_value=true;#bool
value.value=39;#int
pairValue.first=1;#int
pairValue.second=2;#long
tupleValue.0=4;#int
tupleValue.1=5;#short
tupleValue.2=6;#long long
When a callable has an std::optional<T> parameter, ASkeleTon tries to
generate at least two cases when possible so the generated data covers both:
- a present value (
has_value=true) - an empty optional (
has_value=false)
Reproducible Runs
Use --seed to make data generation deterministic. For fully reproducible
outputs across machines, keep these inputs identical:
- LLVM/Clang major version (e.g., 18).
- The exact
compile_commands.json. data/type_factories.jsonanddata/default_values.json.data/system_files.json(or disable auto-create with--no-system-files-refresh).
Report JSON
Use --report or --report-json to generate a JSON summary of the run with:
- Per-entity status:
generatedorskipped. - Skip reasons and related type details when generation is not possible.
- The selected
coverage_mode. - The selected
oracle_mode. - Aggregate counts and coverage metrics.
Common reason values:
abstract_record: type is abstract and cannot be instantiated for fixture setup.non_public_lifecycle: destructor/lifecycle is not publicly usable.missing_fixture_strategy: record cannot be constructed and no factory is configured.missing_instance_strategy: no valid instance plan for method invocation.coverage_policy_mutable_parameter: skipped by strict coverage policy.unsupported_pointer_pointee: pointee type is not auto-materializable.
Full guide with didactic examples and fixes:
Repository Evidence The main manuscript claims map to repository artifacts as follows:
compile_commands.json+ Clang AST analysis:src/askeleton.cpp,doc/Architecture.md- Supported backends (
gtest,boost,catch):src/framework/,data/templates/ - Separate editable test data and test logic:
scripts/check_main_workflow.sh - JSON report and execution log:
src/Report.cpp,--report,--log-json - Explicit-oracle refinement in the minimal reproducibility workflow:
scripts/check_main_workflow.sh,REPRODUCIBILITY.md - Seeded generation and the available profiles/oracle modes:
doc/CLI.md,--seed,--profile,--oracle-mode - Framework extensibility points:
include/framework/Generator.hpp,doc/Architecture.md
Troubleshooting
compile_commands.jsonnot found: pass-p <build-path>to its directory.compile_commands.jsonuses relative paths: supported. ASkeleTon normalizes entries internally so relative entries still match absolute source paths.- Headers not found in fixture: add the include manually in
*_fixture.hpp. - Empty containers in
boundaryprofile: userandomorsafe. llvm-config-18 not found: installllvm-18andllvm-18-tools.- Link errors mentioning
APINotesManager: installlibclang-18-dev. - Link errors for external symbols (e.g. OpenSSL internals): the generated test may need extra project libraries during link; this is project-specific and must be provided in the generated Makefile/link flags.
- If a constructor or method is skipped, check the report reason and the
guidance in
doc/SkipReasons.md.
Docs
- CLI reference:
doc/CLI.md - Architecture overview:
doc/Architecture.md - Rule catalog:
doc/DataRules.md - Release checklist:
doc/ReleaseChecklist.md - Known issues:
doc/KnownIssues.md - Skip reasons guide:
doc/SkipReasons.md - Instance strategies:
doc/InstanceStrategies.md - Type factories:
doc/TypeFactories.md - Dependencies:
doc/Dependencies.md - Examples:
examples/README.md - Reproducibility:
REPRODUCIBILITY.md
Citation
Use CITATION.cff to cite the software version used in the
paper. Release metadata for archival deposition is tracked in
.zenodo.json and should be updated with the final DOI when the
archival record is minted.
License
ASkeleTon is released under the Apache License 2.0. See
LICENSE.txt.
Bundled third-party code retains its own license notices. In particular,
the vendored nlohmann/json headers under include/nlohmann/ retain their
upstream SPDX notices.
If you are working with C++ headers, use the option -xc++.
Authors
- Kevin J. Valle-Gómez (kevin.valle@uca.es)
- Pedro Delgado-Pérez (pedro.delgado@uca.es)
- Inmaculada Medina-Bulo (inmaculada.medina@uca.es)
Acknowledgements: José Manuel Heredia Bravo for his constant maintenance, support and help.