Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Empty file added source/_static/.gitkeep
Empty file.
35 changes: 35 additions & 0 deletions source/common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,41 @@ Specifics of how to implement semantic versioning, such as `versionneer` and
specific documentation of each programming language.


Unit Testing
============

Unit testing is an important part of software development. It helps ensure that the code
is working as expected, helps catch bugs early and verify that the code is not regressing
when feature or changes are made. Testing suites are only expected to grow over time.

A *unit test* is an automated check that a small, isolated piece of
code—typically a single function or method—behaves correctly. Unit
tests are distinct from integration tests (which test interactions
between components) or end-to-end tests (which test a complete
workflow). The goal is to catch regressions quickly and to give
developers confidence that individual components are correct before
combining them.

All codeabases regardless of programming language should include unit tests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
All codeabases regardless of programming language should include unit tests.
All codebases regardless of programming language should include unit tests.


Designing good unit tests
-------------------------

Good unit tests share a few properties:

- **Isolated**: Each test exercises one code path and does not depend
on state left by another test. Tests that share mutable global
state or that must run in a specific order are fragile.
- **Deterministic**: A test should produce the same result every time.
Avoid relying on wall-clock time, random seeds, or external network
resources unless the test explicitly controls them.
- **Fast**: Unit tests should run in milliseconds. Slow tests
discourage developers from running the suite frequently.
- **Focused**: Test one behavior per test function. When a focused
test fails, its name alone should indicate what broke.
- **Thorough on edge cases**: In addition to the happy path, test
boundary conditions, empty inputs, and expected failure modes.


.. _To join the SO Github organization: https://simonsobs.atlassian.net/wiki/spaces/COL/pages/8978437/Digital+Resources#To-join-the-SO-Github-organization
.. _Policy on Openly Contributed Code: https://simonsobs.atlassian.net/wiki/spaces/COL/pages/2037383173/Digital+Assets+Committee
Expand Down
5 changes: 5 additions & 0 deletions source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
'sphinx.ext.todo',
]

# Prefix auto-generated section labels with the document name so that
# identically named sections in different files (e.g. "Unit Testing" in
# both common.rst and python.rst) don't collide.
autosectionlabel_prefix_document = True

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
76 changes: 64 additions & 12 deletions source/cpp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ single letter names, except for loop variables, even if it is a commonly underst
variable.

We will utilize the following naming conventions:
1. Class and struct names should be in PascalCase, e.g. `MyClass`.
2. Function names should be in camelCase, e.g. `myFunction`.
3. Variable names should be in snake_case, e.g. `my_variable`.
4. Constants should be in ALL_CAPS with underscores, e.g. `MAX_SIZE`.
5. Namespaces should be in snake_case, e.g. `my_namespace`.
#. Class and struct names should be in PascalCase, e.g. `MyClass`.
#. Function names should be in camelCase, e.g. `myFunction`.
#. Variable names should be in snake_case, e.g. `my_variable`.
#. Constants should be in ALL_CAPS with underscores, e.g. `MAX_SIZE`.
#. Namespaces should be in snake_case, e.g. `my_namespace`.


Header Files
Expand Down Expand Up @@ -148,19 +148,70 @@ For example:
Unit Testing
============

Unit testing is an important part of software development. It helps ensure that the code
is working as expected, helps catch bugs early and verify that the code is not regressing
when feature or changes are made. Testing suites are only expected to grow over time.

Due to the importance of unit testing, we will require that all new code be accompanied by at
least one unit test. The unit test should be in a separate file, and should be named
`<name>_test.cpp`, where `<name>` is the name of the file being tested.
`<name>_test.cpp`, where `<name>` is the name of the file being tested. Organize tests
in a ``tests/`` directory at the repository root.

`Catch2`_ is the unit testing framework for C++ we will use for SO as it is easy
`Catch2`_ is the unit testing framework for C++ we will use for SO as it is easy
to use, represents tests as normal boolean expressions and also allows benchmarking code.

Please refer to the Catch2 documentation for more information on how to write unit tests.

To have Catch2 tests picked up by CTest (as used in the CI workflow below), call
``catch_discover_tests`` on your test target in ``CMakeLists.txt``; see the
`Catch2 CMake integration`_ documentation for details.

For CTest to find and build these tests, the root ``CMakeLists.txt`` must enable
testing and pull in the ``tests/`` directory::

# root CMakeLists.txt
enable_testing()
add_subdirectory(tests)

with a ``tests/CMakeLists.txt`` that builds the test binary and registers it::

# tests/CMakeLists.txt
find_package(Catch2 REQUIRED)
add_executable(my_lib_test my_lib_test.cpp)
target_link_libraries(my_lib_test PRIVATE my_lib Catch2::Catch2WithMain)

include(CTest)
include(Catch)
catch_discover_tests(my_lib_test)

Github Actions for Continuous Integration
-----------------------------------------

All SO packages should run their test suite automatically on every
pull request using a continuous integration (CI) service. The SO
Github organization uses GitHub Actions; a minimal workflow that builds
the project and runs its test suite across several compilers looks like::

name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [g++-11, clang++-10]
steps:
- uses: actions/checkout@v3
- run: sudo apt-get update && sudo apt-get install -y ${{ matrix.compiler }}
- run: cmake -B build -DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
- run: cmake --build build
- run: ctest --test-dir build

Place this file at ``.github/workflows/tests.yml`` in your repository.
The CI check must pass before a pull request can be merged. Similarly, you can
set the CI to run linter check to verify that the code is formatted according
to the style guide.

.. important::

CI time costs money, especially when running on Private repos. Please be
considerate and make sure that your tests remain fast and efficient. Another
way to avoid the cost is by making your repo public.

Automatic Semantic Versioning
==============================
Expand Down Expand Up @@ -287,6 +338,7 @@ The variables set after calling ``git_semver(<prefix>)`` are:
.. _cmake-git-semver: https://github.com/nunofachada/cmake-git-semver
.. _Google C++ style guide: https://google.github.io/styleguide/cppguide.html
.. _Catch2: https://github.com/catchorg/Catch2
.. _Catch2 CMake integration: https://github.com/catchorg/Catch2/blob/devel/docs/cmake-integration.md

.. note::

Expand Down
Loading
Loading