|
|
|
|
|
This document gives a short overview over the global coding guidelines for IHTA C++ code.
|
|
|
|
|
|
## General C++ guidelines
|
|
|
|
|
|
When in doubt and these guidelines do not cover your problem, checkout [cpp-best-practices](https://github.com/cpp-best-practices/cppbestpractices) by Jason Turner.
|
|
|
|
|
|
### Formatting
|
|
|
|
|
|
All IHTA C++ projects include a `.clang-format` as well as a `.cmake-format`.
|
|
|
|
|
|
**clang-format** is part of the llvm libraries and is usually included in your Visual Studio installation. Your code must be formatted accrodingly. For example, you can quickly format the current selection in Visual Studio using the hotkey combination `Ctrl+K, Ctrl+F`.
|
|
|
|
|
|
**cmake-format** is part of the [cmakelang](https://cmake-format.readthedocs.io/en/latest/#) project and needs to be installed separately.
|
|
|
In case you are editing CMake files extensively, please install it and adhere to the format defined in `.cmake-format`.
|
|
|
|
|
|
### Naming conventions
|
|
|
|
|
|
IHTA mostly follows a **[lowercase camelCase](https://en.wikipedia.org/wiki/Camel_case), [Hungarian](https://en.wikipedia.org/wiki/Hungarian_notation) notation**.
|
|
|
This means, that a class member variable of type `std::vector<Object*>` would have to be named something like `m_vpoNameOfTheVariable`.
|
|
|
Where `m_` denotes it as a class member, `v` stands for the vector, `p` for the fact that it is a pointer and `o` because it is a non specific object.
|
|
|
|
|
|
This naming convention extends to class names as well using **uppercase camelcase**: A class is prefixed with a `C`, a struct with a `S` and an interface with an `I` (e.g. `CMyClass`, `SMyStruct`, `IMyInterface`).
|
|
|
|
|
|
### Use const ref for parameters
|
|
|
|
|
|
To significantly increase the performance (especially for large objects), always use const references for input parameters to a method instead of creating copies:<br/>
|
|
|
`void foo(const std::vector<int>& vec)` instead of `void foo(std::vector<int> vec)`.
|
|
|
|
|
|
In some special cases, it might make sense to use a non-const reference (e.g. pseudo output parameter `void foo(double& dOutput)`), but this should be used with caution.
|
|
|
|
|
|
### Use smart pointers
|
|
|
|
|
|
Raw pointers are evil.
|
|
|
C++11 introduced smart pointers with `std::unique_ptr`, `std::shared_ptr` and `std::weak_ptr`.
|
|
|
Used them over raw pointers.
|
|
|
Preferably, use `unique_ptr`s over `shared_ptr`s, note however, that this requires you to be careful with object destruction.
|
|
|
|
|
|
### Use `nullptr`
|
|
|
|
|
|
C++11 introduces `nullptr` which is a special value denoting a null pointer.
|
|
|
This should be used instead of `0` or `NULL` to indicate a null pointer.
|
|
|
|
|
|
### Use namespaces
|
|
|
|
|
|
When you write code for a library, at least use a namespace with the name of the library.
|
|
|
|
|
|
### Documentation
|
|
|
|
|
|
**Document your code!!**
|
|
|
|
|
|
When you write a new method or class at least document the interface.
|
|
|
What does this method do?
|
|
|
What are the parameters and, if any, return values.
|
|
|
Follow the [doxygen](https://doxygen.nl/manual/docblocks.html) style, preferably using the `///` or `//!` notation.
|
|
|
|
|
|
In the best case, the rest of your source code is self explanatory and does not need any further documentation.
|
|
|
|
|
|
## Unit test guideline
|
|
|
|
|
|
Going forward IHTA uses [catch2](https://github.com/catchorg/Catch2) and [FakeIt](https://github.com/eranpeer/FakeIt) for unit testing.
|
|
|
|
|
|
Any new functionality that is implemented should be unit tested. Try to break your code and test every code path that you can.
|
|
|
|
|
|
An example for a unit test can be found [here](https://git.rwth-aachen.de/ita/ITABase/-/blob/feature/piecewisepolynomal_speedup/tests/UnitTest/ITABaseUnitTestPiesewisePolynomials.cpp).
|
|
|
|
|
|
### Test case naming and tags
|
|
|
|
|
|
Test cases should be named using the following formula:
|
|
|
|
|
|
> [library name]::[class or function under test]/[description of what is tested]
|
|
|
|
|
|
For example leading to `ITABase::PiecewisePolynomial/General`.
|
|
|
Also try to reduce whitespace in the test name.
|
|
|
|
|
|
catch2 also supports using tags for a test case.
|
|
|
Here also use tags with:
|
|
|
|
|
|
- The library name
|
|
|
- The class or function name
|
|
|
- A test priority tag (`[Required]`, `[Recommended]`, `[Optional]`)
|
|
|
|
|
|
### Interface faking
|
|
|
|
|
|
When you want to test your code and you are dependant on an external interface, it is often easier to fake or mock this object.
|
|
|
That way, you can also test if your code is calling the interface correctly.
|
|
|
For this, we use [FakeIt](https://github.com/eranpeer/FakeIt)
|
|
|
For example on how to use this, visit the [FakeIt quick start](https://github.com/eranpeer/FakeIt/wiki/Quickstart)
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
- When verifying a invocation using FakeIt the caller parameters might not be stored correctly.
|
|
|
This happened especially for non trivial types.
|
|
|
In this case, the following workaround can be employed:
|
|
|
|
|
|
```cpp
|
|
|
VAVec3 vecCall;
|
|
|
int idCall;
|
|
|
fakeit::When( Method( VACoreMock, SetSoundReceiverPosition ) )
|
|
|
.AlwaysDo(
|
|
|
[&]( const int& id, const VAVec3& vec )
|
|
|
{
|
|
|
vecCall = vec;
|
|
|
idCall = id;
|
|
|
} );
|
|
|
```
|
|
|
|
|
|
### Use generator expression
|
|
|
|
|
|
catch2 implements a powerful feature with its generator expressions.
|
|
|
Try to use them as often as you can to generate input data or test cases for your tests.
|
|
|
|
|
|
When you want to test for random input data, also use the random generator.
|
|
|
This allows us to repeat a random unit test run using the seeding mechanism of catch2. |