Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c673bd95bb | ||
|
|
b2912e5b61 | ||
|
|
b1ccfd43e0 | ||
|
|
dd0b9fe8ea | ||
|
|
d88090d6b6 | ||
|
|
1c99ff8350 | ||
|
|
2ef695f8fb | ||
|
|
d0a2852119 | ||
|
|
5343ba9dae | ||
|
|
3d1e962107 | ||
|
|
c14d7a7791 | ||
|
|
4f3745f8ec | ||
|
|
dadfd60ed3 | ||
|
|
6c8fea7309 | ||
|
|
9d9e3b1a4d | ||
|
|
54425a306a | ||
|
|
be601f514d | ||
|
|
a7c7c8190c | ||
|
|
44948de7d0 | ||
|
|
e2efde2d1a | ||
|
|
6630116ba1 | ||
|
|
1f7c2b6a92 | ||
|
|
10ad6b74eb | ||
|
|
f62de567df | ||
|
|
d96dc79943 | ||
|
|
e35c301605 | ||
|
|
7af8dba9f3 | ||
|
|
caa80a30d1 | ||
|
|
db4928e78f | ||
|
|
af96fa2cda | ||
|
|
c08ef9070b | ||
|
|
6fe5b43bc1 | ||
|
|
b3056aedd0 | ||
|
|
b2912950c9 | ||
|
|
af2e47308c | ||
|
|
37be3a413a | ||
|
|
a7281b7b1e | ||
|
|
23d06c4bc7 | ||
|
|
b5f522d8bc | ||
|
|
283792715c | ||
|
|
d7032eb351 | ||
|
|
589c280bdc | ||
|
|
9f85d09736 | ||
|
|
d45e5360cc | ||
|
|
58d2a8b58f | ||
|
|
d51820476b | ||
|
|
bfce801cc5 | ||
|
|
63f32e4d8b | ||
|
|
0fc5d208bb | ||
|
|
8b3b500034 | ||
|
|
a5fddf1bb2 | ||
|
|
f3dc0274c3 | ||
|
|
515bf11c3d | ||
|
|
a254c17fcb | ||
|
|
7e9959c455 | ||
|
|
a57e543701 | ||
|
|
43d4b86943 | ||
|
|
81cdd0db81 | ||
|
|
b76bb1002e | ||
|
|
dea940222e | ||
|
|
4a075cc187 | ||
|
|
e17c10c965 | ||
|
|
8c96c02468 | ||
|
|
4260f94ce7 | ||
|
|
21f73e4eae | ||
|
|
743173df81 | ||
|
|
17b6ea23b4 | ||
|
|
840398c073 | ||
|
|
93384e4c37 | ||
|
|
566b11026e | ||
|
|
8fd2986a92 | ||
|
|
e7dd2cf434 | ||
|
|
cdfbf8795a | ||
|
|
d110ddad10 | ||
|
|
36cecf3acc | ||
|
|
066eaec993 | ||
|
|
746ebf9b02 | ||
|
|
1deffe6a98 | ||
|
|
7ac61f1cac | ||
|
|
e386c86316 | ||
|
|
da84eb027f | ||
|
|
1d9f2a2744 | ||
|
|
c1d0f46366 | ||
|
|
99bf00d27c | ||
|
|
7fd43bba2c | ||
|
|
48f14267e5 | ||
|
|
b785a4fbec | ||
|
|
3aa5ddfc32 | ||
|
|
c2277edb56 | ||
|
|
d82ec219f6 | ||
|
|
dc007c84ab | ||
|
|
ccd04b86d3 | ||
|
|
0531a37133 | ||
|
|
566cff8ded | ||
|
|
74c5e92d4b | ||
|
|
aaa374c8ed | ||
|
|
2a6902dbb5 | ||
|
|
02206a8967 | ||
|
|
af2a5a18b3 | ||
|
|
1d0e325813 | ||
|
|
f4e22a5c96 | ||
|
|
fb468f8594 | ||
|
|
4ff0aaad9c | ||
|
|
c0eb5e2087 | ||
|
|
c795635469 | ||
|
|
e844b9949d | ||
|
|
5c807e1859 | ||
|
|
b2edaf69c1 | ||
|
|
dfa6d043b3 | ||
|
|
5e3f01f350 | ||
|
|
f9a098d67b | ||
|
|
3324e27dee | ||
|
|
25f1c62d2c | ||
|
|
afd6ce0a1f | ||
|
|
fb62473b0b | ||
|
|
9b1bc82353 | ||
|
|
d1f0b517e4 | ||
|
|
ec50159a15 | ||
|
|
a7f513fd7c | ||
|
|
698024d47d | ||
|
|
eb8d91470b | ||
|
|
780f22818e | ||
|
|
fdcf9f7099 | ||
|
|
ec0445ec54 | ||
|
|
75f50cd5bb | ||
|
|
4d1af3ce9c | ||
|
|
7b6aa046f4 | ||
|
|
844f6ed86f | ||
|
|
7a8cbe202e | ||
|
|
ec2a4648e1 | ||
|
|
186682b6d4 | ||
|
|
db6811450e | ||
|
|
1c19b51fda | ||
|
|
28cad446b7 | ||
|
|
84867cc474 | ||
|
|
13c644efdc | ||
|
|
5085c35269 | ||
|
|
7682f1285e | ||
|
|
74a0cf012b | ||
|
|
d356e2e79f | ||
|
|
fe027b7fc7 | ||
|
|
501134c2fd | ||
|
|
debe2e63cb | ||
|
|
4452ec50fb | ||
|
|
f034f45b93 | ||
|
|
5160486dcd | ||
|
|
876c586620 | ||
|
|
85ef6faf7d | ||
|
|
6004a76884 | ||
|
|
944829a6be | ||
|
|
9b75a426c5 | ||
|
|
d6d63b7f88 | ||
|
|
d9adde161c | ||
|
|
3d45bbe12a | ||
|
|
90be761780 | ||
|
|
22c5cfdffd | ||
|
|
7834f61662 | ||
|
|
cafb1ef28d | ||
|
|
4211374126 | ||
|
|
cfa50198ee | ||
|
|
f4c1cebfd0 | ||
|
|
7cef499e67 | ||
|
|
e40da83827 | ||
|
|
d916dc4a9d | ||
|
|
791cc93f5f | ||
|
|
1df72dc2e0 | ||
|
|
cf3a9f6ae3 | ||
|
|
946f4b4339 | ||
|
|
e88a0b5ca3 | ||
|
|
6d23e01a82 | ||
|
|
0f8c6039ce | ||
|
|
2abae1c673 | ||
|
|
1e16d7b521 | ||
|
|
55dade8b51 | ||
|
|
2e53d3e4c9 | ||
|
|
4a0ce23184 | ||
|
|
02535eeeb2 | ||
|
|
6d49968a59 | ||
|
|
84ae416c2c | ||
|
|
dd4fd4d187 | ||
|
|
ade001359b | ||
|
|
ac2d3d6b33 | ||
|
|
537ea258ca | ||
|
|
32302c6a80 | ||
|
|
5ba969c561 | ||
|
|
5a4e60f645 | ||
|
|
456feb645a | ||
|
|
556a82e42b | ||
|
|
57f7b6d000 | ||
|
|
67a0b128f7 | ||
|
|
f60f08327c | ||
|
|
72c01bebba | ||
|
|
dede4695e9 | ||
|
|
5efefd3576 | ||
|
|
516eaa2086 | ||
|
|
c3a6f0b624 | ||
|
|
6594cddb65 | ||
|
|
bf2343015e | ||
|
|
228bcf5014 | ||
|
|
589263e902 | ||
|
|
02bdf755a3 | ||
|
|
61fe92e201 | ||
|
|
1b7264793e | ||
|
|
13fc56c24a | ||
|
|
18a6628d0e | ||
|
|
5746ab5ed9 | ||
|
|
ac90991a27 | ||
|
|
531d39d888 | ||
|
|
68576e9a95 | ||
|
|
f7d9956665 | ||
|
|
aa0c2e520f | ||
|
|
9ea48c7298 | ||
|
|
c065e55ca1 | ||
|
|
2c163503d9 | ||
|
|
212b6bfe4f | ||
|
|
ea6998dcad | ||
|
|
d6ec442945 | ||
|
|
6da27f7e86 | ||
|
|
50d605b5b4 | ||
|
|
b147a3db3e | ||
|
|
6018f35598 | ||
|
|
fccf448b3a | ||
|
|
0cd846728c | ||
|
|
876e29973c | ||
|
|
351f5edaa9 | ||
|
|
6edcf19694 | ||
|
|
73463e5c23 | ||
|
|
21267acb8c | ||
|
|
9889f8792f | ||
|
|
ae5a327116 | ||
|
|
8b12bb45c3 | ||
|
|
a32b9fb8a9 | ||
|
|
eb44ed1bc5 | ||
|
|
5fe252934c | ||
|
|
3c4a740759 | ||
|
|
29555ed584 | ||
|
|
f454b9df2d | ||
|
|
6266ce3c6c | ||
|
|
d0cfd73fab | ||
|
|
985700c79d | ||
|
|
e650fa4d8b | ||
|
|
72b2173dfc | ||
|
|
7f688e0fa4 | ||
|
|
c8f79c36b4 | ||
|
|
396ea3daf3 | ||
|
|
c4b2c1d760 | ||
|
|
0bf4ef711e | ||
|
|
affdd497ec | ||
|
|
6b6bd2e369 | ||
|
|
466b4f9a0f | ||
|
|
e90aad5994 | ||
|
|
338c8a8eee | ||
|
|
a390c3daa6 | ||
|
|
9e0dbe67e6 | ||
|
|
6b02bf5df0 | ||
|
|
029f519005 | ||
|
|
b6248459be | ||
|
|
51e3b2a1f7 | ||
|
|
b2504e9477 | ||
|
|
ec6ddd1c5c | ||
|
|
60705fe93b | ||
|
|
cf407da41b | ||
|
|
5435feb932 | ||
|
|
02e4f8e536 | ||
|
|
db090f9164 | ||
|
|
70967beebf | ||
|
|
5b7c2f6dbb | ||
|
|
2d7a3a4dd9 | ||
|
|
01d699fc74 | ||
|
|
6ed82f821f | ||
|
|
c59fa32efe | ||
|
|
dbdb0e4686 | ||
|
|
fc0df14992 | ||
|
|
a5771f1af9 | ||
|
|
4db097b0b0 | ||
|
|
65e4c4f7ac | ||
|
|
d1df4b2fad | ||
|
|
5009fbfbe4 | ||
|
|
cbfcf2bb3c | ||
|
|
63e16d0bac | ||
|
|
cd58c6ce90 | ||
|
|
6787b3c1fe | ||
|
|
980ff6f150 | ||
|
|
ef5f97ad88 | ||
|
|
9ad97c8390 | ||
|
|
8256ea2115 | ||
|
|
b6f97ba0a4 | ||
|
|
88a36c6f57 | ||
|
|
8932460b8c | ||
|
|
7e570cea45 | ||
|
|
1d781d3d54 | ||
|
|
c1070e375f | ||
|
|
582d4ad5cd | ||
|
|
907c9ac423 | ||
|
|
f9c805648a | ||
|
|
94e3e864bc | ||
|
|
53acbd9594 | ||
|
|
085f066958 | ||
|
|
594f177160 | ||
|
|
c53166f630 | ||
|
|
64f4a8077e | ||
|
|
a4bfdcefa8 | ||
|
|
e6b83c7473 | ||
|
|
107292a328 | ||
|
|
9f31c845ee | ||
|
|
3acee26d05 | ||
|
|
1b260fd745 | ||
|
|
02dd6176d7 | ||
|
|
d19c6acadd | ||
|
|
911ec96207 | ||
|
|
1cefc9d9ba | ||
|
|
da1b73feee | ||
|
|
8ce7d781a4 | ||
|
|
3db5941757 | ||
|
|
8b925ae0c4 | ||
|
|
ea7f65725e | ||
|
|
137736d6eb | ||
|
|
d0136e6a71 | ||
|
|
9abb0ff3a9 | ||
|
|
b706b114b3 | ||
|
|
3085c037ba | ||
|
|
c34ddd32a5 | ||
|
|
3c10a1e12a | ||
|
|
a154a813ad | ||
|
|
3b5c7365a1 | ||
|
|
0f78b7e91c | ||
|
|
cf93bf008f | ||
|
|
2bbe7788f1 | ||
|
|
025348bfe3 | ||
|
|
4cf809b579 | ||
|
|
9e1d92a7bc | ||
|
|
ef94137edc | ||
|
|
910f71ec9e | ||
|
|
f4973cdb4b | ||
|
|
4dcc8e23e7 | ||
|
|
044193c7ed | ||
|
|
29b2bb6635 | ||
|
|
d9f0314655 | ||
|
|
af6c230edc | ||
|
|
01746ab16d | ||
|
|
5865134b29 | ||
|
|
39d033c50d | ||
|
|
f64b3bc82d | ||
|
|
3f2353cc57 | ||
|
|
bc20a790da | ||
|
|
a238770418 | ||
|
|
90eb339a05 | ||
|
|
fa16ff964e | ||
|
|
ebb864f234 | ||
|
|
01a33b97a7 | ||
|
|
8b05464444 | ||
|
|
977396e852 | ||
|
|
84b6e84c49 | ||
|
|
33b96b459e | ||
|
|
a095f9f6bd | ||
|
|
828558bfcc | ||
|
|
e49b0cbf8c | ||
|
|
39fc4b2997 | ||
|
|
5d2925fd94 | ||
|
|
f6a2a1cab5 | ||
|
|
661bcfe56e | ||
|
|
821da2ce29 | ||
|
|
38ee3fabd9 | ||
|
|
ac54d29f66 | ||
|
|
b27b04ebf0 | ||
|
|
055438e740 |
@@ -2,22 +2,28 @@
|
||||
|
||||
# Exceptions:
|
||||
# bugprone-branch-clone is too noisy in parsing code.
|
||||
# cert-dcl50-cpp is triggered by debug_print()'s C style.
|
||||
# bugprone-easily-swappable-parameters is too noisy.
|
||||
# cert-dcl50-cpp is triggered by hz::string_sprintf()'s C style.
|
||||
# clang-analyzer-deadcode.DeadStores is too noisy.
|
||||
# clang-analyzer-cplusplus.NewDeleteLeaks doesn't understand Gtkmm memory management.
|
||||
# cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers is triggered by attribute database.
|
||||
# cppcoreguidelines-avoid-do-while is triggered in DBG macros.
|
||||
# cppcoreguidelines-owning-memory doesn't support deleting Gtkmm objects.
|
||||
# cppcoreguidelines-pro-type-cstyle-cast needed by GTK C casts.
|
||||
# cppcoreguidelines-pro-type-reinterpret-cast is needed by WinAPI-facing functions
|
||||
# cppcoreguidelines-pro-type-vararg is triggered by libdebug's debug_print().
|
||||
# cppcoreguidelines-pro-bounds-array-to-pointer-decay is triggered by va_start in libdebug's debug_print().
|
||||
# cppcoreguidelines-pro-type-vararg is triggered by hz::string_sprintf().
|
||||
# cppcoreguidelines-pro-bounds-array-to-pointer-decay is triggered by va_start in hz::string_sprintf().
|
||||
# cppcoreguidelines-pro-bounds-pointer-arithmetic is useless (triggered by argv) until we have std::span.
|
||||
# misc-include-cleaner does not really work.
|
||||
# misc-no-recursion is too noisy.
|
||||
# modernize-raw-string-literal is very noisy.
|
||||
# modernize-use-trailing-return-type is contrary to our style.
|
||||
# performance-enum-size is too noisy.
|
||||
# readability-avoid-unconditional-preprocessor-if is triggered on platform-specific code
|
||||
# readability-convert-member-functions-to-static is triggered for many callbacks.
|
||||
# readability-function-cognitive-complexity needed by UI constructors.
|
||||
# readability-isolate-declaration is noisy.
|
||||
# readability-identifier-length is too noisy.
|
||||
|
||||
|
||||
Checks: >
|
||||
@@ -27,6 +33,7 @@ Checks: >
|
||||
-boost-*,
|
||||
bugprone-*,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
cert-*,
|
||||
-cert-dcl50-cpp,
|
||||
clang-analyzer-*,
|
||||
@@ -35,6 +42,7 @@ Checks: >
|
||||
concurrency-*,
|
||||
cppcoreguidelines-*,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
@@ -49,6 +57,7 @@ Checks: >
|
||||
-llvm-*,
|
||||
-llvmlibc-*,
|
||||
misc-*,
|
||||
-misc-include-cleaner,
|
||||
-misc-no-recursion,
|
||||
modernize-*,
|
||||
-modernize-use-trailing-return-type,
|
||||
@@ -57,12 +66,15 @@ Checks: >
|
||||
-objc-*,
|
||||
openmp-*,
|
||||
performance-*,
|
||||
-performance-enum-size,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-readability-avoid-unconditional-preprocessor-if,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-identifier-length,
|
||||
-zircon-*
|
||||
|
||||
WarningsAsErrors: ''
|
||||
@@ -82,6 +94,8 @@ CheckOptions:
|
||||
value: '0'
|
||||
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||
value: '1'
|
||||
- key: misc-include-cleaner.IgnoreHeaders
|
||||
value: 'libdebug/*;local_glibmm.h;glib/*;gtk/*;gtkmm/*;glibmm/*'
|
||||
- key: performance-unnecessary-value-param.AllowedTypes
|
||||
value: 'RefPtr;Ptr$'
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug, enhancement
|
||||
assignees: ashaduri
|
||||
|
||||
---
|
||||
|
||||
**Version and Environment**
|
||||
- GSmartControl version: [Are you using the latest released version or git?]
|
||||
- OS: [e.g. openSUSE Linux 15.5]
|
||||
|
||||
**Describe the Bug**
|
||||
[A clear and concise description of what the bug is].
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Screenshots**
|
||||
[If applicable, add screenshots to help explain your problem].
|
||||
|
||||
**Additional Context**
|
||||
[Add any other context about the problem here (GTK+ version, etc.)]
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ashaduri
|
||||
|
||||
---
|
||||
|
||||
**Version and Environment**
|
||||
- GSmartControl version: [Are you using the latest released version or git?]
|
||||
- OS: [e.g. openSUSE Linux 15.5]
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: Other issue
|
||||
about: Issues other than bugs and enhancements
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ashaduri
|
||||
|
||||
---
|
||||
|
||||
**Version and Environment**
|
||||
- GSmartControl version: [Are you using the latest released version or git?]
|
||||
- OS: [e.g. openSUSE Linux 15.5]
|
||||
|
||||
**Describe the Issue**
|
||||
[A clear and concise description of what the issue is].
|
||||
@@ -0,0 +1,124 @@
|
||||
# GSmartControl – Copilot Instructions
|
||||
|
||||
GSmartControl is a C++20 GTK3/Gtkmm GUI for inspecting hard-drive and SSD health via SMART data
|
||||
(wrapping `smartctl` from smartmontools). It supports Linux, Windows (MSYS2/MinGW), macOS, and BSDs.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
|
||||
# Standard Linux build (uses dev toolchain with warnings enabled)
|
||||
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../toolchains/linux-dev.cmake
|
||||
|
||||
# Windows (MSYS2/MinGW64)
|
||||
cmake .. -G "MSYS Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../toolchains/win64-mingw-msys2.cmake
|
||||
|
||||
# Build on MSYS2/MinGW64 (from build dir)
|
||||
cmake --build . --target all -j 18
|
||||
```
|
||||
|
||||
The `configure-dev` script is a convenience wrapper: `./configure-dev -t <toolchain> -c <compiler> -b <build_type>`.
|
||||
|
||||
Key CMake options:
|
||||
- `-DAPP_BUILD_TESTS=ON` – enable test targets
|
||||
- `-DAPP_BUILD_EXAMPLES=ON` – enable example targets
|
||||
- `-DAPP_COMPILER_ENABLE_WARNINGS=ON` – strict compiler warnings (set automatically by `linux-dev.cmake`)
|
||||
|
||||
## Tests
|
||||
|
||||
Tests use **Catch2** (vendored in `dependencies/catch2/`). They are only built when `-DAPP_BUILD_TESTS=ON` is passed.
|
||||
|
||||
```bash
|
||||
# Build and run all tests
|
||||
cmake .. -DAPP_BUILD_TESTS=ON
|
||||
cmake --build .
|
||||
ctest -C RelWithDebInfo --rerun-failed --output-on-failure
|
||||
|
||||
# Run a single test executable directly (from build dir)
|
||||
./test_all "[smartctl_parser]" # Catch2 tag filter
|
||||
./test_all "test name substring" # substring match
|
||||
```
|
||||
|
||||
Test sources live in `src/applib/tests/` and `src/hz/tests/`; they are linked into `src/test_all/`.
|
||||
|
||||
## Linting
|
||||
|
||||
Clang-tidy config is at `.clang-tidy` in the repo root. Run it via CMake or directly:
|
||||
|
||||
```bash
|
||||
clang-tidy src/applib/storage_device.cpp -- -std=c++20 $(pkg-config --cflags gtkmm-3.0)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The codebase is split into libraries and one GUI executable:
|
||||
|
||||
| Component | Location | Purpose |
|
||||
|---|---|---|
|
||||
| `applib` | `src/applib/` | Core logic: SMART parsing, device detection, command execution |
|
||||
| `hz` | `src/hz/` | General-purpose C++ utilities (strings, filesystem, error types) |
|
||||
| `rconfig` | `src/rconfig/` | Runtime config load/save with auto-save support |
|
||||
| `libdebug` | `src/libdebug/` | Debug logging with named channels |
|
||||
| `gui` | `src/gui/` | GTK/Gtkmm UI (windows, dialogs, Glade `.ui` files) |
|
||||
|
||||
### Parsing pipeline
|
||||
|
||||
`smartctl` output is parsed through a strategy pattern:
|
||||
- JSON parsers (`smartctl_json_ata_parser`, `smartctl_json_nvme_parser`, `smartctl_json_basic_parser`) target smartctl ≥ 7.3.
|
||||
- Text parsers (`smartctl_text_ata_parser`, `smartctl_text_basic_parser`) handle legacy output.
|
||||
- Parsed results are stored as `StorageProperty` objects in a `StoragePropertyRepository` on `StorageDevice`.
|
||||
|
||||
### Device detection
|
||||
|
||||
`StorageDetector` is an abstract interface; platform implementations are:
|
||||
- `storage_detector_linux.cpp` – scans `/dev/sd*`, `/dev/nvme*`, etc.
|
||||
- `storage_detector_win32.cpp` – WMI/registry enumeration
|
||||
- `storage_detector_other.cpp` – generic `/dev` scanning (BSD/macOS)
|
||||
|
||||
### Async execution
|
||||
|
||||
`AsyncCommandExecutor` wraps `CommandExecutor` (which shells out to `smartctl`) in a background thread.
|
||||
Completion is signalled via **libsigc++** signals back to the GTK main loop. Never call GTK APIs from the worker thread;
|
||||
queue them through signals or `Glib::signal_idle()`.
|
||||
|
||||
### Error handling
|
||||
|
||||
Use `hz::ExpectedValue<T, E>` (wrapping `tl::expected`) for recoverable errors instead of exceptions.
|
||||
Enum-based error types (`StorageDeviceError`, `SmartctlParserError`) are preferred over string errors.
|
||||
|
||||
## Key Conventions
|
||||
|
||||
**Naming:**
|
||||
- Classes: `PascalCase` (e.g., `StorageDevice`, `SmartctlParser`)
|
||||
- Methods and members: `snake_case`; private/member fields have a trailing `_` (e.g., `device_list_`)
|
||||
- GUI classes in `src/gui/` are prefixed `Gsc` (e.g., `GscMainWindow`)
|
||||
- Filenames: `snake_case.cpp` / `snake_case.h`
|
||||
|
||||
**Headers:**
|
||||
- Use `#ifndef FILENAME_H` / `#define FILENAME_H` guards (not `#pragma once`)
|
||||
- Include order: standard library → third-party (GTK/Gtkmm) → project headers
|
||||
- All project headers are included relative to `src/` (the include root)
|
||||
|
||||
**Modern C++20/23 patterns used throughout:**
|
||||
- `std::optional<T>` for nullable values
|
||||
- `hz::ExpectedValue<T, E>` for error-returning functions
|
||||
- `std::string_view` for non-owning string parameters
|
||||
- `fmt::format()` (vendored `fmt` library) for string formatting
|
||||
- Smart pointers exclusively; no raw owning pointers
|
||||
|
||||
**Vendored dependencies** are in `dependencies/` and added via `add_subdirectory`.
|
||||
Do not modify them; prefer upgrading the whole vendored copy.
|
||||
|
||||
**Translations:** UI strings are wrapped with `_()` (gettext). `.po` files live in `po/`.
|
||||
Translations are not yet supported.
|
||||
|
||||
**Platform guards:** Use `#ifdef CONFIG_KERNEL_FAMILY_WINDOWS`,
|
||||
`#ifdef CONFIG_KERNEL_LINUX`, etc.
|
||||
|
||||
## Agentic Development
|
||||
|
||||
Place all plans and temporary files in `agent_workspace/`. This directory is ignored by Git.
|
||||
@@ -13,54 +13,107 @@ on:
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
SMARTMONTOOLS_INSTALLER: smartmontools-7.2-1.win32-setup.exe
|
||||
SMARTMONTOOLS_URL: https://nav.dl.sourceforge.net/project/smartmontools/smartmontools/7.2/smartmontools-7.2-1.win32-setup.exe
|
||||
SMARTMONTOOLS_INSTALLER: smartmontools-7.4-1.win32-setup.exe
|
||||
SMARTMONTOOLS_URL: https://downloads.sourceforge.net/project/smartmontools/smartmontools/7.4/smartmontools-7.4-1.win32-setup.exe
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
linux-ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
linux-ubuntu-24_04:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Update Package Database
|
||||
run: sudo apt-get update
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install libpcre3-dev libgtkmm-3.0-dev gettext
|
||||
run: sudo apt-get install libgtkmm-3.0-dev gettext
|
||||
|
||||
- name: Create Build Directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
run: cmake -E make_directory build
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
env:
|
||||
CC: gcc-14
|
||||
CXX: g++-14
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DAPP_BUILD_EXAMPLES=ON
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: bash
|
||||
run: ctest -C $BUILD_TYPE
|
||||
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
|
||||
- name: Pack (cmake install and make binary package)
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G TBZ2
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Linux Packages
|
||||
path: ${{runner.workspace}}/build/gsmartcontrol-*-Linux*.*
|
||||
path: ${{github.workspace}}/build/gsmartcontrol-*-Linux*.*
|
||||
|
||||
|
||||
linux-ubuntu-22_04:
|
||||
# GCC 11
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Update Package Database
|
||||
run: sudo apt-get update
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install libgtkmm-3.0-dev gettext
|
||||
|
||||
- name: Create Build Directory
|
||||
run: cmake -E make_directory build
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
env:
|
||||
CC: gcc-11
|
||||
CXX: g++-11
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/linux-dev.cmake"
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: bash
|
||||
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
|
||||
- name: Pack (cmake install and make binary package)
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G TBZ2
|
||||
|
||||
# - name: Upload artifacts
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: Linux Packages
|
||||
# path: ${{github.workspace}}/build/gsmartcontrol-*-Linux*.*
|
||||
|
||||
|
||||
windows-msys2:
|
||||
@@ -68,12 +121,13 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: MINGW64, arch: x86_64 },
|
||||
{ msystem: MINGW32, arch: i686 }
|
||||
{ msystem: MINGW64, arch: x86_64, platform: win64, urlpath: mingw64 },
|
||||
# MSYS2 no longer supports for 32-bit Windows.
|
||||
# { msystem: MINGW32, arch: i686, platform: win32, urlpath: mingw32 }
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
# p7zip is needed to extract smartmontools
|
||||
@@ -87,79 +141,109 @@ jobs:
|
||||
mingw-w64-${{ matrix.arch }}-cmake
|
||||
mingw-w64-${{ matrix.arch }}-gcc
|
||||
mingw-w64-${{ matrix.arch }}-fontconfig
|
||||
mingw-w64-${{ matrix.arch }}-nsis
|
||||
make
|
||||
p7zip
|
||||
|
||||
- name: Configure CMake
|
||||
- name: Downgrade Packages to support Windows 7
|
||||
# librsvg 2.59 requires Windows 8.1 or later (confirmed by dependency walker).
|
||||
# We need to downgrade to 2.58.
|
||||
# This contains gdk_pixbuf loader as well, and re-runs the loader cache update.
|
||||
# https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
# https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: >
|
||||
cmake -B build -S "$GITHUB_WORKSPACE" -G "MSYS Makefiles"
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DAPP_BUILD_EXAMPLES=ON
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
|
||||
- name: Build
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: msys2 {0}
|
||||
run: ctest -C $BUILD_TYPE
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
wget https://repo.msys2.org/mingw/${{ matrix.urlpath }}/mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
pacman -U --noconfirm mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
|
||||
- name: Download Package Requirements
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
mkdir smartmontools
|
||||
cd smartmontools
|
||||
mkdir -p build/smartmontools
|
||||
cd build/smartmontools
|
||||
wget $SMARTMONTOOLS_URL
|
||||
|
||||
- name: Extract Package Requirements (64-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build/smartmontools
|
||||
working-directory: ${{github.workspace}}/build/smartmontools
|
||||
run: >
|
||||
7z -bb1 e $SMARTMONTOOLS_INSTALLER
|
||||
bin64/smartctl.exe
|
||||
bin64/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.exe
|
||||
bin/smartctl.exe
|
||||
bin/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.ps1
|
||||
bin/drivedb.h
|
||||
|
||||
- name: Extract Package Requirements (32-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build/smartmontools
|
||||
working-directory: ${{github.workspace}}/build/smartmontools
|
||||
run: >
|
||||
7z -bb1 e $SMARTMONTOOLS_INSTALLER
|
||||
bin/smartctl.exe
|
||||
bin/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.exe
|
||||
bin32/smartctl.exe
|
||||
bin32/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.ps1
|
||||
bin/drivedb.h
|
||||
|
||||
- name: List installed files
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
ls -1R /mingw64
|
||||
ls -1R /mingw32
|
||||
|
||||
- name: List Files in Workspace
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}
|
||||
run: ls -1R .
|
||||
|
||||
- name: Configure CMake
|
||||
shell: msys2 {0}
|
||||
run: >
|
||||
cmake -B build -S "$GITHUB_WORKSPACE"
|
||||
-G "MSYS Makefiles"
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/${{ matrix.platform }}-mingw-msys2.cmake"
|
||||
|
||||
- name: Build
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: msys2 {0}
|
||||
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
|
||||
- name: Package ZIP
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G ZIP
|
||||
|
||||
- name: Package NSIS (64-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G NSIS64
|
||||
|
||||
- name: Package NSIS (32-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G NSIS
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows Packages
|
||||
path: ${{runner.workspace}}/build/gsmartcontrol-*-win*.*
|
||||
name: Windows 64-Bit Packages
|
||||
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
|
||||
|
||||
- name: Upload artifacts
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows 32-Bit Packages
|
||||
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Build (Tier 2 platforms with flaky builds)
|
||||
|
||||
# FreeBSD build via vmactions/freebsd-vm is known to fail randomly,
|
||||
# so we don't want it to be triggered on every commit.
|
||||
|
||||
# Manually triggered
|
||||
on: [workflow_dispatch]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
CXX: clang++-17
|
||||
|
||||
jobs:
|
||||
|
||||
freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
# env:
|
||||
# variables to pass to VM
|
||||
# MYTOKEN : ${{ secrets.MYTOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build and test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
envs: 'BUILD_TYPE CXX'
|
||||
usesh: true
|
||||
sync: rsync
|
||||
# release: "14.0"
|
||||
prepare: >
|
||||
pkg install -y cmake pkgconf gtkmm30 gettext libiconv llvm17
|
||||
|
||||
run: >
|
||||
mkdir build && cd build
|
||||
|
||||
cmake ..
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DAPP_BUILD_EXAMPLES=ON
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
|
||||
cmake --build . --config $BUILD_TYPE
|
||||
|
||||
ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
@@ -1,7 +1,14 @@
|
||||
name: Build (Tier 2 platforms)
|
||||
|
||||
# Manually triggered
|
||||
on: [workflow_dispatch]
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
@@ -12,19 +19,31 @@ jobs:
|
||||
|
||||
macos-homebrew:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include: [
|
||||
# We need AppleClang 16, but GitHub only has 14 for now.
|
||||
# { compiler: apple-clang },
|
||||
{ compiler: clang }
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Dependencies
|
||||
run: brew install pkg-config gtkmm3 pcre cmake
|
||||
run: brew install pkg-config gtkmm3 cmake
|
||||
|
||||
- name: Install Clang Compiler
|
||||
if: ${{ matrix.compiler == 'clang' }}
|
||||
run: brew install llvm@17
|
||||
|
||||
- name: Create Build Directory
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
run: cmake -E make_directory build
|
||||
|
||||
- name: Configure CMake
|
||||
- name: Configure CMake (Apple Clang)
|
||||
if: ${{ matrix.compiler == 'apple-clang' }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
@@ -32,45 +51,25 @@ jobs:
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
|
||||
- name: Configure CMake
|
||||
if: ${{ matrix.compiler == 'clang' }}
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DAPP_BUILD_EXAMPLES=ON
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
-DCMAKE_CXX_COMPILER=$(brew --prefix llvm@17)/bin/clang++
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: bash
|
||||
run: ctest -C $BUILD_TYPE
|
||||
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
|
||||
|
||||
freebsd:
|
||||
runs-on: macos-latest
|
||||
# env:
|
||||
# variables to pass to VM
|
||||
# MYTOKEN : ${{ secrets.MYTOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build and test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0.1.2
|
||||
with:
|
||||
envs: 'BUILD_TYPE'
|
||||
usesh: true
|
||||
sync: rsync
|
||||
mem: 2048
|
||||
prepare: >
|
||||
pkg install -y cmake pkgconf gtkmm30 gettext pcre libiconv
|
||||
|
||||
run: >
|
||||
mkdir build && cd build
|
||||
|
||||
cmake ..
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DAPP_BUILD_EXAMPLES=ON
|
||||
-DAPP_BUILD_TESTS=ON
|
||||
-DAPP_COMPILER_ENABLE_WARNINGS=ON
|
||||
|
||||
cmake --build . --config $BUILD_TYPE
|
||||
|
||||
ctest -C $BUILD_TYPE
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# This workflow checks out code, performs a Codacy security scan
|
||||
# and integrates the results with the
|
||||
# GitHub Advanced Security code scanning feature. For more information on
|
||||
# the Codacy security scan action usage and parameters, see
|
||||
# https://github.com/codacy/codacy-analysis-cli-action.
|
||||
# For more information on Codacy Analysis CLI in general, see
|
||||
# https://github.com/codacy/codacy-analysis-cli.
|
||||
|
||||
name: Codacy Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '27 22 * * 1'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
||||
name: Codacy Security Scan
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b
|
||||
with:
|
||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||
# You can also omit the token and run the tools that support default configurations
|
||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
verbose: true
|
||||
output: results.sarif
|
||||
format: sarif
|
||||
# Adjust severity of non-security issues
|
||||
gh-code-scanning-compat: true
|
||||
# Force 0 exit code to allow SARIF file generation
|
||||
# This will handover control about PR rejection to the GitHub side
|
||||
max-allowed-issues: 2147483647
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF results file
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -0,0 +1,85 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '24 10 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
#packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
#actions: read
|
||||
#contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Update Package Database
|
||||
run: sudo apt-get update
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get install libgtkmm-3.0-dev gettext
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
env:
|
||||
CC: gcc-13
|
||||
CXX: g++-13
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
@@ -0,0 +1,36 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
name: DevSkim
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '25 22 * * 0'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: DevSkim
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run DevSkim scanner
|
||||
uses: microsoft/DevSkim-Action@v1
|
||||
with:
|
||||
ignore-globs: dummy_to_avoid_action_error,**/.git/**,*.txt,**/dependencies/**,env_tools.h,app_gtkmm_tools.cpp
|
||||
|
||||
- name: Upload DevSkim scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: devskim-results.sarif
|
||||
@@ -0,0 +1,140 @@
|
||||
name: Windows Release
|
||||
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
SMARTMONTOOLS_INSTALLER: smartmontools-7.4-1.win32-setup.exe
|
||||
SMARTMONTOOLS_URL: https://downloads.sourceforge.net/project/smartmontools/smartmontools/7.4/smartmontools-7.4-1.win32-setup.exe
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
windows-msys2:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: MINGW64, arch: x86_64, platform: win64, urlpath: mingw64 },
|
||||
{ msystem: MINGW32, arch: i686, platform: win32, urlpath: mingw32 }
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
# p7zip is needed to extract smartmontools
|
||||
# fontconfig owns /etc/fonts
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
install: >-
|
||||
mingw-w64-${{ matrix.arch }}-gtkmm3
|
||||
mingw-w64-${{ matrix.arch }}-pkg-config
|
||||
mingw-w64-${{ matrix.arch }}-cmake
|
||||
mingw-w64-${{ matrix.arch }}-gcc
|
||||
mingw-w64-${{ matrix.arch }}-fontconfig
|
||||
make
|
||||
p7zip
|
||||
|
||||
- name: Downgrade Packages to support Windows 7
|
||||
# librsvg 2.59 requires Windows 8.1 or later (confirmed by dependency walker).
|
||||
# We need to downgrade to 2.58.
|
||||
# This contains gdk_pixbuf loader as well, and re-runs the loader cache update.
|
||||
# https://repo.msys2.org/mingw/mingw32/mingw-w64-i686-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
# https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
wget https://repo.msys2.org/mingw/${{ matrix.urlpath }}/mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
pacman -U --noconfirm mingw-w64-${{ matrix.arch }}-librsvg-2.58.0-1-any.pkg.tar.zst
|
||||
|
||||
- name: Download Package Requirements
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
mkdir -p build/smartmontools
|
||||
cd build/smartmontools
|
||||
wget $SMARTMONTOOLS_URL
|
||||
|
||||
- name: Extract Package Requirements (64-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build/smartmontools
|
||||
run: >
|
||||
7z -bb1 e $SMARTMONTOOLS_INSTALLER
|
||||
bin/smartctl.exe
|
||||
bin/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.ps1
|
||||
bin/drivedb.h
|
||||
|
||||
- name: Extract Package Requirements (32-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build/smartmontools
|
||||
run: >
|
||||
7z -bb1 e $SMARTMONTOOLS_INSTALLER
|
||||
bin32/smartctl.exe
|
||||
bin32/smartctl-nc.exe
|
||||
bin/update-smart-drivedb.ps1
|
||||
bin/drivedb.h
|
||||
|
||||
- name: List installed files
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
ls -1R /mingw64
|
||||
ls -1R /mingw32
|
||||
|
||||
- name: Configure CMake
|
||||
shell: msys2 {0}
|
||||
run: >
|
||||
cmake -B build -S "$GITHUB_WORKSPACE"
|
||||
-G "MSYS Makefiles"
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||
-DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/toolchains/${{ matrix.platform }}-mingw-msys2.cmake"
|
||||
|
||||
- name: Build
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: msys2 {0}
|
||||
run: ctest -C $BUILD_TYPE --rerun-failed --output-on-failure
|
||||
|
||||
- name: Package ZIP
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G ZIP
|
||||
|
||||
- name: Package NSIS (64-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G NSIS64
|
||||
|
||||
- name: Package NSIS (32-bit)
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
shell: msys2 {0}
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cpack -G NSIS
|
||||
|
||||
- name: Upload artifacts
|
||||
if: ${{ matrix.msystem == 'MINGW64' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows 64-Bit Packages
|
||||
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
|
||||
|
||||
- name: Upload artifacts
|
||||
if: ${{ matrix.msystem == 'MINGW32' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows 32-Bit Packages
|
||||
path: ${{github.workspace}}/build/gsmartcontrol-*-win*.*
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
# Builds
|
||||
/0*
|
||||
/doxygen_doc*
|
||||
/win32*
|
||||
/win64*
|
||||
/cmake-build-*
|
||||
/build*
|
||||
/_codeql_build_dir
|
||||
|
||||
# Non-project files
|
||||
/TODO
|
||||
@@ -28,6 +29,9 @@ Thumbs.db
|
||||
/.idea
|
||||
/CMakeLists.txt.user
|
||||
|
||||
# Agents
|
||||
/.codebuddy
|
||||
|
||||
# Translations
|
||||
/po/boldquot.sed
|
||||
/po/en@boldquot.header
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
# This file describes OBS workflows:
|
||||
# https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.scm_ci_workflow_integration.html
|
||||
|
||||
# Workflow for pull requests
|
||||
#build_pull_request_workflow:
|
||||
# steps:
|
||||
# - branch_package:
|
||||
# source_project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
# source_package: gsmartcontrol
|
||||
# target_project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
#
|
||||
# - configure_repositories:
|
||||
# project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
# repositories:
|
||||
# - name: openSUSE_Tumbleweed
|
||||
# paths:
|
||||
# - target_project: openSUSE:Factory
|
||||
# target_repository: snapshot
|
||||
# architectures:
|
||||
# - x86_64
|
||||
# - i586
|
||||
#
|
||||
# - set_flags:
|
||||
# flags:
|
||||
# - type: publish
|
||||
# status: disable
|
||||
# project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
#
|
||||
# filters:
|
||||
# event: pull_request
|
||||
# branches:
|
||||
# only:
|
||||
# - main
|
||||
|
||||
|
||||
# Workflow for pushes
|
||||
|
||||
# Note: This adds new repositories to the project if they do not exist.
|
||||
build_main_workflow:
|
||||
steps:
|
||||
- configure_repositories:
|
||||
project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
repositories:
|
||||
|
||||
- name: openSUSE_Tumbleweed
|
||||
paths:
|
||||
- target_project: openSUSE:Factory
|
||||
target_repository: snapshot
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: openSUSE_Slowroll
|
||||
paths:
|
||||
- target_project: openSUSE:Slowroll
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: openSUSE_Leap_15.6
|
||||
paths:
|
||||
- target_project: openSUSE:Leap:15.6
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: openSUSE_Leap_15.5
|
||||
paths:
|
||||
- target_project: devel:gcc
|
||||
target_repository: openSUSE_Leap_15.5
|
||||
- target_project: openSUSE:Leap:15.5
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: openSUSE_Factory_ARM
|
||||
paths:
|
||||
- target_project: openSUSE:Factory:ARM
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- aarch64
|
||||
- armv7l
|
||||
|
||||
- name: SUSE_SLE-15-SP6
|
||||
paths:
|
||||
- target_project: devel:gcc
|
||||
target_repository: SLE-15
|
||||
- target_project: SUSE:SLE-15-SP6:GA
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Ubuntu_24.04
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: xUbuntu_24.04
|
||||
- target_project: Ubuntu:24.04
|
||||
target_repository: universe
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Ubuntu_23.10
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: xUbuntu_23.10
|
||||
- target_project: Ubuntu:23.10
|
||||
target_repository: universe
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Ubuntu_22.04
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: xUbuntu_22.04
|
||||
- target_project: Ubuntu:22.04
|
||||
target_repository: universe
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Fedora_Rawhide
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Fedora_Rawhide
|
||||
- target_project: Fedora:Rawhide
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Fedora_41
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Fedora_41
|
||||
- target_project: Fedora:41
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
- aarch64
|
||||
|
||||
- name: Fedora_40
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Fedora_40
|
||||
- target_project: Fedora:40
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
- aarch64
|
||||
|
||||
- name: Fedora_39
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Fedora_39
|
||||
- target_project: Fedora:39
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
- aarch64
|
||||
|
||||
- name: Debian_Unstable
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Debian_Unstable
|
||||
- target_project: Debian:Next
|
||||
target_repository: standard
|
||||
architectures:
|
||||
- x86_64
|
||||
|
||||
- name: Debian_Testing
|
||||
paths:
|
||||
- target_project: openSUSE:Tools
|
||||
target_repository: Debian_Testing
|
||||
- target_project: Debian:Testing
|
||||
target_repository: update
|
||||
architectures:
|
||||
- x86_64
|
||||
- i586
|
||||
|
||||
- set_flags:
|
||||
flags:
|
||||
- type: publish
|
||||
status: enable
|
||||
project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
- type: debuginfo
|
||||
status: enable
|
||||
project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
|
||||
- rebuild_package:
|
||||
project: home:alex_sh:gsmartcontrol:github_ci:main
|
||||
package: gsmartcontrol
|
||||
|
||||
filters:
|
||||
event: push
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
###############################################################################
|
||||
# License: BSD Zero Clause License file
|
||||
# Copyright:
|
||||
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
# (C) 2021 - 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
# 3.12 for CMAKE_PROJECT_VERSION
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
# 3.14 for proper object library support (wrt linking)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
# Use new policy for option() to supress warnings.
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
@@ -20,7 +20,7 @@ project(gsmartcontrol
|
||||
)
|
||||
|
||||
|
||||
# Provide DATADIR, etc...
|
||||
# Provide DATADIR, etc.
|
||||
include(GNUInstallDirs)
|
||||
|
||||
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
@@ -55,8 +55,8 @@ if (WIN32)
|
||||
PATTERN "CNAME" EXCLUDE
|
||||
)
|
||||
else()
|
||||
install(FILES ${DOC_FILES} DESTINATION "${CMAKE_INSTALL_DOCDIR}/")
|
||||
install(DIRECTORY docs DESTINATION "${CMAKE_INSTALL_DOCDIR}/"
|
||||
install(FILES ${DOC_FILES} TYPE DOC)
|
||||
install(DIRECTORY docs TYPE DOC
|
||||
PATTERN "*.yml" EXCLUDE
|
||||
PATTERN "CNAME" EXCLUDE
|
||||
)
|
||||
@@ -65,7 +65,8 @@ endif()
|
||||
|
||||
# CTest support
|
||||
include(CTest)
|
||||
include(${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/extras/Catch.cmake)
|
||||
#include(${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/extras/Catch.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/contrib/Catch.cmake)
|
||||
|
||||
|
||||
add_subdirectory(contrib)
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
ashaduri@gmail.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,3 +1,69 @@
|
||||
Version 2.0.2, released on 2025-02-24
|
||||
Support GCC 11 (and Ubuntu 22.04) by using and vendoring fmt library
|
||||
(#77).
|
||||
Support an option of saving smartctl output to text instead of JSON (#76).
|
||||
Restored pre-2.0.0 runtime support for smartctl < 7.3 (based on Text
|
||||
parser); this is an unsupported, old method without NVMe, provided
|
||||
for compatibility only (#77).
|
||||
Restored pre-2.0.0 support for standard (non-extended) self-test log found
|
||||
in very old ATA drives; the new JSON parser did not support this
|
||||
previously (#79).
|
||||
Better support for temperature values in JSON parser; this fixes
|
||||
unreasonably large temperature values (#78).
|
||||
Add a tooltip explaining self-test "lifetime hours" wrapping behavior
|
||||
(#73).
|
||||
Windows: Fixed a crash on Windows 7 when opening drive information
|
||||
by using Windows 7-compatible librsvg (#71).
|
||||
Windows: Avoid using non-integer font sizes.
|
||||
|
||||
Version 2.0.1, released on 2024-11-26
|
||||
Windows: Fixed a crash when opening a native file dialog (#67).
|
||||
|
||||
Version 2.0.0, released on 2024-11-07
|
||||
New JSON-based parser for smartctl output (requires smartctl 7.3+) (#4).
|
||||
Support for NVMe drives (self-tests require smartctl 7.4+) (#4).
|
||||
New "Basic" JSON parser for SCSI, flash, and other non-ATA/NVMe drives.
|
||||
PCRE library is no longer required (the code has been ported to
|
||||
std::regex) (#40).
|
||||
A lot of code has been refactored and modernized using C++17 and C++20
|
||||
features, removing much of the custom library code.
|
||||
The build process requires a C++20-compliant compiler now (GCC 13+,
|
||||
Clang 17+, Apple Clang 15+).
|
||||
CMake (3.14+) is now used as a build system instead of autotools.
|
||||
GSmartControl is now licensed under GNU GPL 3 only.
|
||||
Icons come from Oxygen project now (LGPL 3+) instead of Crystal project.
|
||||
Documentation in md format comes with the source code ("docs" directory).
|
||||
Support new versions and prereleases of smartctl (#46, #42).
|
||||
Better detection of drive types thanks to the JSON parser.
|
||||
Removed ATA AODC feature, it has been deprecated for a while now.
|
||||
Information window: Some values are aligned and monospaced to improve
|
||||
readability.
|
||||
Fixed command execution popup dialog being on top of all windows (#17).
|
||||
Other minor UI improvements and fixes.
|
||||
Windows: Better support for HiDPI (including fractional scaling).
|
||||
Windows: NSIS package is generated by CPack now.
|
||||
Windows: Packages are built using GitHub CI now.
|
||||
|
||||
Version 1.1.4, released on 2022-02-04
|
||||
Fixed a crash when trying to render main window icons which have
|
||||
incomplete data; this fixes a rare crash when scanning devices (#13).
|
||||
Fixed rendering compatibility issues with newer GTK3 versions.
|
||||
Fixed build system conflict with C++20 version header (#14).
|
||||
Fixed "Running command ..." dialog floating above windows of other
|
||||
applications (#17).
|
||||
Fixed a crash when system locale is set to invalid locale.
|
||||
Support Finnish decimal separator (backported from the Debian package)
|
||||
(#23).
|
||||
Set LC_NUMERIC=C for smartctl process to avoid locale-dependent number
|
||||
formatting (#23).
|
||||
Fixed printing all GTK messages as warnings; the messages are sorted by
|
||||
severity now.
|
||||
Add current time to default filename in Save Output dialog.
|
||||
Support macos stat command in file2csource.sh.
|
||||
Fixed a few typos (backported from the Debian package).
|
||||
Windows port now uses Adwaita theme due to issues with win32 theme.
|
||||
Windows port is dpi-aware now.
|
||||
|
||||
Version 1.1.3, released on 2017-11-12
|
||||
Fixed gsmartcontrol-root not launching if GDK_* variables are not set.
|
||||
|
||||
@@ -113,7 +179,7 @@ Version 0.8.6, released on 2011-06-12
|
||||
included.
|
||||
In-program help has been expanded considerably.
|
||||
General improvements to user interface have been implemented (better GNOME
|
||||
HIG compliance, better tooltips, dialogs, etc...).
|
||||
HIG compliance, better tooltips, dialogs, etc.).
|
||||
Added ability to show smartctl output for devices whose info could not be
|
||||
parsed fully.
|
||||
Attributes in "brief" format are supported now.
|
||||
|
||||
@@ -1,105 +1,65 @@
|
||||
|
||||
# GSmartControl
|
||||
|
||||
### Hard disk drive and SSD health inspection tool
|
||||
***Hard disk drive and SSD health inspection tool***
|
||||
|
||||
[](https://gsmartcontrol.shaduri.dev)
|
||||
[](https://gsmartcontrol.shaduri.dev/downloads)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://gsmartcontrol.shaduri.dev/software-requirements)
|
||||
[](https://repology.org/project/gsmartcontrol/versions)
|
||||
[](https://app.codacy.com/gh/ashaduri/gsmartcontrol?utm_source=github.com&utm_medium=referral&utm_content=ashaduri/gsmartcontrol&utm_campaign=Badge_Grade_Settings)
|
||||
|
||||
[GSmartControl](https://gsmartcontrol.shaduri.dev/)
|
||||
---
|
||||
|
||||
[GSmartControl](https://gsmartcontrol.shaduri.dev)
|
||||
is a graphical user interface for smartctl (from [smartmontools](https://www.smartmontools.org/)
|
||||
package), which is a tool for
|
||||
querying and controlling [SMART](https://en.wikipedia.org/wiki/S.M.A.R.T.)
|
||||
querying and controlling [SMART](https://en.wikipedia.org/wiki/Self-Monitoring,_Analysis_and_Reporting_Technology)
|
||||
(Self-Monitoring, Analysis, and Reporting
|
||||
Technology) data on modern hard disk and solid-state drives. It allows you to
|
||||
inspect the drive's SMART data to determine its health, as well as run various
|
||||
tests on it.
|
||||
|
||||
GSmartControl supports ATA drives (both PATA and SATA), various USB to
|
||||
ATA bridges and drives behind some RAID controllers:
|
||||
* Adaptec (Linux, some models only)
|
||||
* Areca (Linux, Windows)
|
||||
* HP CCISS (Linux)
|
||||
* HP hpsa / hpahcisr (Linux)
|
||||
* Intel Matrix Storage (CSMI) (Linux, Windows, FreeBSD)
|
||||
* LSI 3ware (Linux, Windows)
|
||||
* LSI MegaRAID (Windows)
|
||||
|
||||
Note: Smartmontools supports even more RAID Controllers. The drives
|
||||
behind such controllers can be manually added to GSmartControl using
|
||||
"Add Device..." functionality or `--add-device` command-line option.
|
||||
See [Supported RAID Controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers).
|
||||
## Downloads
|
||||
|
||||
The [Downloads](https://gsmartcontrol.shaduri.dev/downloads) page contains
|
||||
all the available packages of GSmartControl.
|
||||
|
||||
|
||||
## Software Requirements
|
||||
|
||||
Note: If using the official Windows package, no additional software is required.
|
||||
|
||||
### Build Requirements
|
||||
* [pcre1](https://www.pcre.org)
|
||||
* [GTK+ 3](https://www.gtk.org), version 3.4 or higher
|
||||
* [Gtkmm](https://www.gtkmm.org), version 3.4 or higher
|
||||
|
||||
### Runtime Requirements
|
||||
* [smartmontools](https://www.smartmontools.org/)
|
||||
* xterm (optional)
|
||||
|
||||
### Supported Operating Systems
|
||||
* Linux - All the popular configurations should work.
|
||||
* FreeBSD - Tested with DesktopBSD / x86.
|
||||
* NetBSD - Tested with NetBSD / x86.
|
||||
* OpenBSD - Tested with OpenBSD / x86-64.
|
||||
* DragonFlyBSD - Code written but no testing has been performed yet. Expected
|
||||
to work without any issues.
|
||||
* Windows Vista SP2 (32-bit and 64-bit), Windows 7 SP1, Windows Server 2008,
|
||||
Windows 8.1, Windows 10. The Windows port uses pd0, pd1, etc...
|
||||
for physical drives 0, 1, etc... .
|
||||
* Mac OS X.
|
||||
* Solaris.
|
||||
* QNX - Code written but no testing has been performed yet.
|
||||
## Features
|
||||
- automatically reports and highlights any anomalies;
|
||||
- allows enabling/disabling SMART;
|
||||
- supports configuration of global and per-drive options for smartctl;
|
||||
- performs SMART self-tests;
|
||||
- displays drive identity information, capabilities, attributes, device statistics, etc.;
|
||||
- can read in smartctl output from a saved file, interpreting it as a read-only virtual device;
|
||||
- works on most smartctl-supported operating systems;
|
||||
- has extensive help information.
|
||||
|
||||
|
||||
## Usage
|
||||
### Supported Hardware
|
||||
|
||||
### Command-Line Options
|
||||
GSmartControl supports SATA, PATA, and NVMe drives, as well as drives
|
||||
behind some USB bridges and RAID controllers.
|
||||
Please see the
|
||||
[Supported Hardware](https://gsmartcontrol.shaduri.dev/supported-hardware) page
|
||||
for more information.
|
||||
|
||||
GSmartControl inherits options from GTK+ and other libraries, so be sure to
|
||||
run it with `--help` option to get a full list of accepted parameters.
|
||||
Note: The Windows version may not have a text output at all, so `--help` and
|
||||
similar arguments won't have any effect.
|
||||
|
||||
The most important parameters are:
|
||||
|
||||
`-?`, `--help` - Show help options.
|
||||
|
||||
`-l`, `--no-locale` - Don't use system locale.
|
||||
|
||||
`-V`, `--version` - Display version information.
|
||||
|
||||
`--no-scan` - Don't scan devices on startup.
|
||||
|
||||
`--no-hide-tabs` - Don't hide non-identity tabs when SMART is disabled. Useful
|
||||
for debugging.
|
||||
|
||||
`--add-virtual <file>` - Load smartctl data from file, creating a virtual drive. You
|
||||
can specify this option multiple times.
|
||||
|
||||
`--add-device <device>::<type>[::<extra_args>]` - Add a device to device list.
|
||||
This option is useful with `--no-scan` to list certain drives only. You can specify
|
||||
this option multiple times.
|
||||
Example:
|
||||
`--add-device /dev/sda --add-device /dev/twa0::3ware,2 --add-device
|
||||
'/dev/sdb::::-T permissive'`.
|
||||
|
||||
`-v`, `--verbose` - Enable verbose logging; same as `--verbosity-level 5`.
|
||||
|
||||
`-q`, `--quiet` - Disable logging; same as `--verbosity-level 0`.
|
||||
|
||||
`-b`, `--verbosity-level` - Set verbosity level [0-5].
|
||||
### Supported Platforms
|
||||
|
||||
GSmartControl supports all major desktop operating systems, including
|
||||
Linux, Windows, macOS, FreeBSD, and other BSD-style operating systems.
|
||||
Please see the
|
||||
[Software Requirements](https://gsmartcontrol.shaduri.dev/software-requirements) page
|
||||
for more information.
|
||||
|
||||
|
||||
## Copyright and Licensing
|
||||
|
||||
GSmartControl is Copyright (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com> and contributors.
|
||||
GSmartControl is Copyright (C) 2008 - 2025 Alexander Shaduri [ashaduri@gmail.com](mailto:ashaduri@gmail.com) and contributors.
|
||||
|
||||
GSmartControl is licensed under the terms of
|
||||
[GNU General Public License Version 3](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
@@ -112,7 +72,5 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public Licenses for more details.
|
||||
|
||||
This product includes icons from Crystal Project,
|
||||
copyright 2006-2007 Everaldo Coelho (https://www.everaldo.com).
|
||||
Crystal Project icons are licensed under [GNU LGPL](https://www.gnu.org/licenses/lgpl-3.0.en.html).
|
||||
|
||||
This product includes icons from Oxygen Icons copyright [KDE](https://kde.org)
|
||||
and licensed under the [GNU LGPL version 3](https://www.gnu.org/licenses/lgpl-3.0.en.html) or later.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The following versions are supported with security updates:
|
||||
|
||||
| Version | Supported |
|
||||
|----------| ------------------ |
|
||||
| git main | :white_check_mark: |
|
||||
| 2.0.x | :white_check_mark: |
|
||||
| < 2.0.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security vulnerabilities privately to
|
||||
Alexander Shaduri [ashaduri@gmail.com](mailto:ashaduri@gmail.com).
|
||||
@@ -0,0 +1 @@
|
||||
*
|
||||
@@ -5,5 +5,6 @@
|
||||
###############################################################################
|
||||
|
||||
if (NOT WIN32)
|
||||
install(DIRECTORY "cron-based_noadmin" DESTINATION "${CMAKE_INSTALL_DOCDIR}/contrib/")
|
||||
install(DIRECTORY "${CMAKE_SOURCE_DIR}/contrib" TYPE DOC
|
||||
PATTERN "CMakeLists.txt" EXCLUDE)
|
||||
endif()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
###############################################################################
|
||||
# License: BSD Zero Clause License file
|
||||
# Copyright:
|
||||
# (C) 2008 - 2021 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
# (C) 2008 - 2024 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
device="$1";
|
||||
@@ -13,10 +13,10 @@ if [ "$device" = "" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
dev_base="`basename \"$device\"`"
|
||||
dev_base=$(basename "$device")
|
||||
out_file=/var/run/smart-"$dev_base"
|
||||
|
||||
# Change the path to smartctl if necessary.
|
||||
smartctl -x "$device" 2>&1 > "$out_file"
|
||||
smartctl -x --json=o "$device" > "$out_file" 2>&1
|
||||
|
||||
chmod 644 "$out_file"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
###############################################################################
|
||||
# License: BSD Zero Clause License file
|
||||
# Copyright:
|
||||
# (C) 2008 - 2021 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
# (C) 2008 - 2022 Alex Butcher <alex dot butcher 'at' assursys.co.uk>
|
||||
# (C) 2008 - 2022 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
if [ "$1" = "-V" ]; then
|
||||
@@ -21,7 +21,7 @@ if [ "$device" = "" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
dev_base="`basename \"$device\"`"
|
||||
dev_base=$(basename "$device")
|
||||
out_file=/var/run/smart-"$dev_base"
|
||||
|
||||
cat "$out_file"
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 632 B |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -26,12 +26,17 @@ if (WIN32)
|
||||
install(FILES gsmartcontrol.ico DESTINATION .)
|
||||
endif()
|
||||
|
||||
set (DATA_ICONS
|
||||
icons/drive-optical.png
|
||||
icons/drive-harddisk.png
|
||||
icons/drive-removable-media-usb.png
|
||||
)
|
||||
|
||||
# Install internal icons
|
||||
if (WIN32)
|
||||
install(FILES icon_cddvd.png icon_hdd.png
|
||||
DESTINATION .)
|
||||
install(FILES ${DATA_ICONS} DESTINATION icons)
|
||||
else()
|
||||
install(FILES icon_cddvd.png icon_hdd.png
|
||||
install(FILES ${DATA_ICONS}
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/gsmartcontrol/icons")
|
||||
endif()
|
||||
|
||||
@@ -49,10 +54,10 @@ if (NOT WIN32)
|
||||
DESTINATION "${CMAKE_INSTALL_DATADIR}/polkit-1/actions/")
|
||||
|
||||
# Man pages
|
||||
install(FILES "gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1/")
|
||||
install(FILES "gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1/" RENAME "gsmartcontrol-root.1")
|
||||
install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
|
||||
install(FILES "man1/gsmartcontrol.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" RENAME "gsmartcontrol-root.1")
|
||||
|
||||
# Scripts (this goes to bin, not sbin, as it doesn't require root privileges before running)
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol-root.sh" DESTINATION "${CMAKE_INSTALL_BINDIR}" RENAME "gsmartcontrol-root")
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/gsmartcontrol-root.sh" TYPE BIN RENAME "gsmartcontrol-root")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
# From https://github.com/vector-of-bool/CMakeCM/blob/master/modules/FindFilesystem.cmake
|
||||
|
||||
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindFilesystem
|
||||
##############
|
||||
|
||||
This module supports the C++17 standard library's filesystem utilities. Use the
|
||||
:imp-target:`std::filesystem` imported target to
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
The ``COMPONENTS`` argument to this module supports the following values:
|
||||
|
||||
.. find-component:: Experimental
|
||||
:name: fs.Experimental
|
||||
|
||||
Allows the module to find the "experimental" Filesystem TS version of the
|
||||
Filesystem library. This is the library that should be used with the
|
||||
``std::experimental::filesystem`` namespace.
|
||||
|
||||
.. find-component:: Final
|
||||
:name: fs.Final
|
||||
|
||||
Finds the final C++17 standard version of the filesystem library.
|
||||
|
||||
If no components are provided, behaves as if the
|
||||
:find-component:`fs.Final` component was specified.
|
||||
|
||||
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
|
||||
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
|
||||
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
|
||||
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
|
||||
|
||||
|
||||
Imported Targets
|
||||
****************
|
||||
|
||||
.. imp-target:: std::filesystem
|
||||
|
||||
The ``std::filesystem`` imported target is defined when any requested
|
||||
version of the C++ filesystem library has been found, whether it is
|
||||
*Experimental* or *Final*.
|
||||
|
||||
If no version of the filesystem library is available, this target will not
|
||||
be defined.
|
||||
|
||||
.. note::
|
||||
This target has ``cxx_std_17`` as an ``INTERFACE``
|
||||
:ref:`compile language standard feature <req-lang-standards>`. Linking
|
||||
to this target will automatically enable C++17 if no later standard
|
||||
version is already required on the linking target.
|
||||
|
||||
|
||||
.. _fs.variables:
|
||||
|
||||
Variables
|
||||
*********
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
|
||||
|
||||
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
|
||||
filesystem library was found, otherwise ``FALSE``.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_HAVE_FS
|
||||
|
||||
Set to ``TRUE`` when a filesystem header was found.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_HEADER
|
||||
|
||||
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
|
||||
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
|
||||
found.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_NAMESPACE
|
||||
|
||||
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
|
||||
depending on whether :find-component:`fs.Final` or
|
||||
:find-component:`fs.Experimental` was found.
|
||||
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
Using `find_package(Filesystem)` with no component arguments:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Filesystem REQUIRED)
|
||||
|
||||
add_executable(my-program main.cpp)
|
||||
target_link_libraries(my-program PRIVATE std::filesystem)
|
||||
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
|
||||
if(TARGET std::filesystem)
|
||||
# This module has already been processed. Don't do it again.
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
|
||||
# If we're not cross-compiling, try to run test executables.
|
||||
# Otherwise, assume that compile + link is a sufficient check.
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
include(CheckCXXSourceCompiles)
|
||||
macro(_cmcm_check_cxx_source code var)
|
||||
check_cxx_source_compiles("${code}" ${var})
|
||||
endmacro()
|
||||
else()
|
||||
include(CheckCXXSourceRuns)
|
||||
macro(_cmcm_check_cxx_source code var)
|
||||
check_cxx_source_runs("${code}" ${var})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
|
||||
|
||||
# All of our tests required C++17 or later
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Normalize and check the component list we were given
|
||||
set(want_components ${Filesystem_FIND_COMPONENTS})
|
||||
if(Filesystem_FIND_COMPONENTS STREQUAL "")
|
||||
set(want_components Final)
|
||||
endif()
|
||||
|
||||
# Warn on any unrecognized components
|
||||
set(extra_components ${want_components})
|
||||
list(REMOVE_ITEM extra_components Final Experimental)
|
||||
foreach(component IN LISTS extra_components)
|
||||
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
|
||||
endforeach()
|
||||
|
||||
# Detect which of Experimental and Final we should look for
|
||||
set(find_experimental TRUE)
|
||||
set(find_final TRUE)
|
||||
if(NOT "Final" IN_LIST want_components)
|
||||
set(find_final FALSE)
|
||||
endif()
|
||||
if(NOT "Experimental" IN_LIST want_components)
|
||||
set(find_experimental FALSE)
|
||||
endif()
|
||||
|
||||
if(find_final)
|
||||
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
# We found the non-experimental header. Don't bother looking for the
|
||||
# experimental one.
|
||||
set(find_experimental FALSE)
|
||||
endif()
|
||||
else()
|
||||
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
|
||||
endif()
|
||||
|
||||
if(find_experimental)
|
||||
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
else()
|
||||
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
|
||||
endif()
|
||||
|
||||
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
set(_have_fs TRUE)
|
||||
set(_fs_header filesystem)
|
||||
set(_fs_namespace std::filesystem)
|
||||
set(_is_experimental FALSE)
|
||||
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
set(_have_fs TRUE)
|
||||
set(_fs_header experimental/filesystem)
|
||||
set(_fs_namespace std::experimental::filesystem)
|
||||
set(_is_experimental TRUE)
|
||||
else()
|
||||
set(_have_fs FALSE)
|
||||
endif()
|
||||
|
||||
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
||||
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
|
||||
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
|
||||
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
|
||||
|
||||
set(_found FALSE)
|
||||
|
||||
if(CXX_FILESYSTEM_HAVE_FS)
|
||||
# We have some filesystem library available. Do link checks
|
||||
string(CONFIGURE [[
|
||||
#include <cstdlib>
|
||||
#include <@CXX_FILESYSTEM_HEADER@>
|
||||
|
||||
int main() {
|
||||
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
|
||||
printf("%s", cwd.c_str());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
]] code @ONLY)
|
||||
|
||||
# Check a simple filesystem program without any linker flags
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
|
||||
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
|
||||
|
||||
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Add the libstdc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
# Try the libc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(can_link)
|
||||
add_library(std::filesystem INTERFACE IMPORTED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||
set(_found TRUE)
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
# Nothing to add...
|
||||
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
|
||||
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
|
||||
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
|
||||
endif()
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
png_name="gsmartcontrol.png"
|
||||
|
||||
# needs imagemagick
|
||||
convert 16/$png_name 22/$png_name 24/$png_name 32/$png_name \
|
||||
48/$png_name 64/$png_name 128/$png_name 256/$png_name gsmartcontrol.ico
|
||||
@@ -2,14 +2,14 @@
|
||||
###############################################################################
|
||||
# License: Zlib
|
||||
# Copyright:
|
||||
# (C) 2008 - 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
# (C) 2008 - 2022 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
# Run gsmartcontrol with root, asking for root password first.
|
||||
# export GSMARTCONTROL_SU to override a su command (e.g. "kdesu -c").
|
||||
|
||||
EXEC_BIN="@CMAKE_INSTALL_FULL_SBINDIR@/gsmartcontrol";
|
||||
prog_name="gsmartcontrol"
|
||||
program_name="gsmartcontrol"
|
||||
|
||||
|
||||
# Preserve quotes in arguments
|
||||
@@ -30,7 +30,7 @@ else
|
||||
# New syntax:
|
||||
# gsmartcontrol-root [--desktop=<auto|kde|gnome|other>] [program_options]
|
||||
|
||||
for arg in $*; do
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--desktop=*)
|
||||
DESKTOP="${arg#*=}";
|
||||
@@ -45,7 +45,7 @@ fi
|
||||
|
||||
if [ "$DESKTOP" != "auto" ] && [ "$DESKTOP" != "kde" ] && \
|
||||
[ "$DESKTOP" != "gnome" ] && [ "$DESKTOP" != "other" ]; then
|
||||
echo "Usage: $0 [--desktop=<auto|kde|gnome|other>] [<${prog_name}_options>]";
|
||||
echo "Usage: $0 [--desktop=<auto|kde|gnome|other>] [<${program_name}_options>]";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
@@ -93,7 +93,7 @@ fi
|
||||
|
||||
if [ "$GSMARTCONTROL_SU" = "" ]; then
|
||||
for subin in $candidates; do
|
||||
which $subin &>/dev/null
|
||||
which "$subin" &>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
found_su="$subin";
|
||||
break;
|
||||
@@ -101,7 +101,7 @@ if [ "$GSMARTCONTROL_SU" = "" ]; then
|
||||
done
|
||||
|
||||
if [ "$found_su" = "" ]; then
|
||||
xmessage "Error launching ${prog_name}: No suitable su mechanism found.
|
||||
xmessage "Error launching ${program_name}: No suitable su mechanism found.
|
||||
Try installing PolKit, kdesu, gnomesu, gksu, beesu or sux first.";
|
||||
exit 1;
|
||||
fi
|
||||
@@ -164,8 +164,5 @@ fi
|
||||
|
||||
|
||||
# echo $full_cmd
|
||||
eval $full_cmd
|
||||
|
||||
|
||||
|
||||
eval "$full_cmd"
|
||||
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Main window</caption>
|
||||
<image>https://gsmartcontrol.sourceforge.io/home/images/main_ok.png</image>
|
||||
<image>https://gsmartcontrol.shaduri.dev/screenshots/main_ok.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Drive identity information</caption>
|
||||
<image>https://gsmartcontrol.sourceforge.io/home/images/info_identity.png</image>
|
||||
<image>https://gsmartcontrol.shaduri.dev/screenshots/info_identity.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Attribute list of a failing drive</caption>
|
||||
<image>https://gsmartcontrol.sourceforge.io/home/images/info_failing.png</image>
|
||||
<image>https://gsmartcontrol.shaduri.dev/screenshots/info_failing.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
</component>
|
||||
|
||||
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 130 KiB |
@@ -13,13 +13,44 @@ Type=Application
|
||||
Categories=System;Monitor;
|
||||
|
||||
Name=GSmartControl
|
||||
Name[ca]=GSControlIntel
|
||||
Name[cs]=GSmartControl
|
||||
Name[es]=GSmartControl
|
||||
Name[id]=GSmartControl
|
||||
Name[it]=GSmartControl
|
||||
Name[ja]=GSmartControl
|
||||
Name[pt_BR]=GSmartControl
|
||||
Name[ru]=GSmartControl
|
||||
Name[sk]=GSmartControl
|
||||
Name[sv]=GSmartControl
|
||||
Name[zh_CN]=GSmartControl
|
||||
# short description, usually shown in parentheses after Name
|
||||
GenericName=Hard Disk and SSD Health Inspection
|
||||
GenericName[ca]=Inspecció de salut del disc dur i de l'SSD
|
||||
GenericName[cs]=Prohlídka zdraví pevných a SSD disků
|
||||
GenericName[es]=Inspección de la salud de discos duros y SSD
|
||||
GenericName[fr]=Inspecteur de santé de disque dur et de SSD
|
||||
GenericName[id]=Pemeriksaan Kesehatan Cakram Keras dan SSD
|
||||
GenericName[it]=Ispezione della salute del disco rigido e dell'SSD
|
||||
GenericName[ja]=ハードディスクと SSD の健全状態の調査
|
||||
GenericName[pt_BR]=Inspeção da integridade de disco rígido e SSD
|
||||
GenericName[ru]=Проверка состояния жёстких и твердотельных дисков
|
||||
GenericName[sk]=Zdravotná inšpekcia pevného disku a SSD
|
||||
GenericName[zh_CN]=机械及固态硬盘健康检测
|
||||
|
||||
# tooltip
|
||||
Comment=Monitor and control SMART data on hard disk and solid-state drives
|
||||
Comment[ca]=Monitoreu i controleu les dades SMART dels discs durs i dels discs sòlids.
|
||||
Comment[cs]=Sleduje a nastavuje SMART data na pevném disku a na polovodičových discích
|
||||
Comment[es]=Monitorice y controle datos de SMART sobre discos duros y unidades de estado sólido
|
||||
Comment[fr]=Surveille et contrôle les données SMART des disques durs et des SSD
|
||||
Comment[id]=Pantau dan kendalikan data cerdas pada cakram keras dan SSD
|
||||
Comment[it]=Monitora e controlla i dati SMART sui dischi rigidi e a stato solido
|
||||
Comment[ja]=ハードディスクや SSD 内の SMART データの監視と制御
|
||||
Comment[pt_BR]=Monitorar e controlar dados do SMART em discos rígidos e unidades de estado sólido
|
||||
Comment[ru]=Мониторинг и контроль данных SMART на жёстких и твердотельных дисках
|
||||
Comment[sk]=Monitorovanie a kontrola údajov SMART na pevných diskoch a diskoch SSD
|
||||
Comment[zh_CN]=监测及控制机械硬盘和固态硬盘上的SMART数据
|
||||
|
||||
# If it's a name only, it looks for "name.[png|xpm]" file in
|
||||
# $XDG_DATA_DIRS/icons.
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
@@ -45,9 +45,6 @@ Display version information
|
||||
\fB\-\-no\-scan\fP
|
||||
Don't scan devices on startup
|
||||
.TP
|
||||
\fB\-\-no\-hide\-tabs\fP
|
||||
Don't hide non\-identity tabs when SMART is disabled. Useful for debugging.
|
||||
.TP
|
||||
\fB\-\-add\-virtual\fP
|
||||
Load smartctl data from file, creating a virtual drive. You
|
||||
can specify this option multiple times.
|
||||
@@ -61,6 +58,9 @@ can specify this option multiple times. Example:\fR
|
||||
\-\-add\-device /dev/sda \-\-add\-device /dev/twa0::3ware,2 \-\-add\-device '/dev/sdb::::-T permissive'
|
||||
.fi
|
||||
.TP
|
||||
\fB\-\-forget\-devices\fP
|
||||
Forget all previously manually added devices
|
||||
.TP
|
||||
\fB\-\-display\fP=\fIDISPLAY\fP
|
||||
X display to use
|
||||
.TP
|
||||
@@ -1,7 +1,7 @@
|
||||
###############################################################################
|
||||
# License: BSD Zero Clause License file
|
||||
# Copyright:
|
||||
# (C) 2021 - 2022 Alexander Shaduri <ashaduri@gmail.com>
|
||||
# (C) 2021 - 2024 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
# Disable all warnings
|
||||
@@ -18,8 +18,8 @@ find_package(PkgConfig REQUIRED) # pkg_check_modules()
|
||||
|
||||
|
||||
# Gtkmm.
|
||||
# Don't make it REQUIRED, we may want to build only the parsers.
|
||||
pkg_check_modules(Gtkmm IMPORTED_TARGET GLOBAL "gtkmm-3.0>=3.0")
|
||||
# Don't make it REQUIRED, we may want to build only the parsers
|
||||
pkg_check_modules(Gtkmm REQUIRED IMPORTED_TARGET GLOBAL "gtkmm-3.0>=3.0")
|
||||
add_library(app_gtkmm_interface INTERFACE)
|
||||
target_link_libraries(app_gtkmm_interface
|
||||
INTERFACE
|
||||
@@ -30,16 +30,13 @@ target_compile_definitions(app_gtkmm_interface
|
||||
ENABLE_GLIB=1
|
||||
ENABLE_GLIBMM=1
|
||||
# For porting to GTK4
|
||||
GTK_DISABLE_DEPRECATED=1
|
||||
GDK_DISABLE_DEPRECATED=1
|
||||
GTKMM_DISABLE_DEPRECATED=1
|
||||
GDKMM_DISABLE_DEPRECATED=1
|
||||
GLIBMM_DISABLE_DEPRECATED=1
|
||||
GIOMM_DISABLE_DEPRECATED=1
|
||||
# GTK_DISABLE_DEPRECATED=1
|
||||
# GDK_DISABLE_DEPRECATED=1
|
||||
# GTKMM_DISABLE_DEPRECATED=1
|
||||
# GDKMM_DISABLE_DEPRECATED=1
|
||||
# GLIBMM_DISABLE_DEPRECATED=1
|
||||
# GIOMM_DISABLE_DEPRECATED=1
|
||||
)
|
||||
# Don't forget to set the following environment variable to catch deprecated properties and signals at runtime:
|
||||
#G_ENABLE_DIAGNOSTIC=1
|
||||
|
||||
|
||||
# Support pre-C++17 glibmm with throw(...) exception specifications
|
||||
pkg_check_modules(Glibmm "glibmm-2.4")
|
||||
@@ -49,21 +46,12 @@ if ("${Glibmm_VERSION}" VERSION_LESS "2.50.1")
|
||||
endif()
|
||||
|
||||
|
||||
# pcrecpp from pcre1
|
||||
pkg_check_modules(Pcrecpp REQUIRED IMPORTED_TARGET GLOBAL libpcrecpp)
|
||||
add_library(app_pcrecpp_interface INTERFACE)
|
||||
target_link_libraries(app_pcrecpp_interface
|
||||
INTERFACE
|
||||
PkgConfig::Pcrecpp
|
||||
)
|
||||
|
||||
|
||||
# Gettext libintl
|
||||
find_package(Intl REQUIRED)
|
||||
add_library(app_gettext_interface INTERFACE)
|
||||
if (Intl_INCLUDE_DIRS)
|
||||
target_include_directories(app_gettext_interface
|
||||
INTERFACE
|
||||
SYSTEM INTERFACE
|
||||
${Intl_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
@@ -76,9 +64,11 @@ endif()
|
||||
|
||||
# Gettext binaries and macros.
|
||||
# See https://cmake.org/cmake/help/v3.15/module/FindGettext.html
|
||||
find_package(Gettext REQUIRED)
|
||||
# find_package(Gettext REQUIRED)
|
||||
|
||||
|
||||
add_subdirectory(catch2)
|
||||
add_subdirectory(fmt)
|
||||
add_subdirectory(nlohmann_json)
|
||||
add_subdirectory(whereami)
|
||||
add_subdirectory(tl_expected)
|
||||
|
||||
@@ -4,8 +4,19 @@
|
||||
# (C) 2021 Alexander Shaduri <ashaduri@gmail.com>
|
||||
###############################################################################
|
||||
|
||||
#set(CATCH_INSTALL_DOCS OFF CACHE INTERNAL "")
|
||||
#set(CATCH_INSTALL_EXTRAS OFF CACHE INTERNAL "")
|
||||
#set(CATCH_DEVELOPMENT_BUILD OFF CACHE INTERNAL "")
|
||||
#add_subdirectory(Catch2)
|
||||
|
||||
|
||||
add_library(Catch2 INTERFACE)
|
||||
|
||||
# Relative sources are allowed only since cmake 3.13.
|
||||
target_sources(Catch2 INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Catch2/single_include/catch2/catch.hpp
|
||||
)
|
||||
|
||||
target_include_directories(Catch2
|
||||
SYSTEM INTERFACE
|
||||
"${CMAKE_SOURCE_DIR}/dependencies/catch2/Catch2/single_include"
|
||||
)
|
||||
|
||||
|
||||
add_subdirectory(Catch2)
|
||||
|
||||
@@ -29,5 +29,3 @@ cmake-build-*
|
||||
benchmark-dir
|
||||
.conan/test_package/build
|
||||
bazel-*
|
||||
build-fuzzers
|
||||
debug-build
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
|
||||
# Avoid repeatedly including the targets
|
||||
if(NOT TARGET Catch2::Catch2)
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
|
||||
endif()
|
||||
@@ -1,157 +0,0 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
# Search for gcov binary.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Gcov evaluation is dependent on the used compiler. Check gcov support for
|
||||
# each compiler that is used. If gcov binary was already found for this
|
||||
# compiler, do not try to find it again.
|
||||
if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN)
|
||||
get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH)
|
||||
|
||||
if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU")
|
||||
# Some distributions like OSX (homebrew) ship gcov with the compiler
|
||||
# version appended as gcov-x. To find this binary we'll build the
|
||||
# suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+" GCC_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov
|
||||
HINTS ${COMPILER_PATH})
|
||||
|
||||
elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang")
|
||||
# Some distributions like Debian ship llvm-cov with the compiler
|
||||
# version appended as llvm-cov-x.y. To find this binary we'll build
|
||||
# the suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
# llvm-cov prior version 3.5 seems to be not working with coverage
|
||||
# evaluation tools, but these versions are compatible with the gcc
|
||||
# gcov tool.
|
||||
if(LLVM_VERSION VERSION_GREATER 3.4)
|
||||
find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}"
|
||||
"llvm-cov" HINTS ${COMPILER_PATH})
|
||||
mark_as_advanced(LLVM_COV_BIN)
|
||||
|
||||
if (LLVM_COV_BIN)
|
||||
find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS
|
||||
${CMAKE_MODULE_PATH})
|
||||
if (LLVM_COV_WRAPPER)
|
||||
set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "")
|
||||
|
||||
# set additional parameters
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV
|
||||
"LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING
|
||||
"Environment variables for llvm-cov-wrapper.")
|
||||
mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT GCOV_BIN)
|
||||
# Fall back to gcov binary if llvm-cov was not found or is
|
||||
# incompatible. This is the default on OSX, but may crash on
|
||||
# recent Linux versions.
|
||||
find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
if (GCOV_BIN)
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING
|
||||
"${LANG} gcov binary.")
|
||||
|
||||
if (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Found gcov evaluation for "
|
||||
"${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}")
|
||||
endif()
|
||||
|
||||
unset(GCOV_BIN CACHE)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target for all gcov targets. This target could be used to
|
||||
# generate the gcov files for the whole project instead of calling <TARGET>-gcov
|
||||
# for each target.
|
||||
if (NOT TARGET gcov)
|
||||
add_custom_target(gcov)
|
||||
endif (NOT TARGET gcov)
|
||||
|
||||
|
||||
|
||||
# This function will add gcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# Gcov on any source file of <TNAME> once and store the gcov file in the same
|
||||
# directory.
|
||||
function (add_gcov_target TNAME)
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(BUFFER "")
|
||||
foreach(FILE ${SOURCES})
|
||||
get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH)
|
||||
|
||||
# call gcov
|
||||
add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov
|
||||
COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null
|
||||
DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno
|
||||
WORKING_DIRECTORY ${FILE_PATH}
|
||||
)
|
||||
|
||||
list(APPEND BUFFER ${TDIR}/${FILE}.gcov)
|
||||
endforeach()
|
||||
|
||||
|
||||
# add target for gcov evaluation of <TNAME>
|
||||
add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER})
|
||||
|
||||
# add evaluation target to the global gcov target.
|
||||
add_dependencies(gcov ${TNAME}-gcov)
|
||||
endfunction (add_gcov_target)
|
||||
@@ -1,354 +0,0 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# configuration
|
||||
set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data")
|
||||
set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init")
|
||||
set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture")
|
||||
set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html")
|
||||
|
||||
|
||||
|
||||
|
||||
# Search for Gcov which is used by Lcov.
|
||||
find_package(Gcov)
|
||||
|
||||
|
||||
|
||||
|
||||
# This function will add lcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# geninfo on any source file of <TNAME> once and store the info file in the same
|
||||
# directory.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_lcov_target TNAME)
|
||||
if (LCOV_FOUND)
|
||||
# capture initial coverage data
|
||||
lcov_capture_initial_tgt(${TNAME})
|
||||
|
||||
# capture coverage data after execution
|
||||
lcov_capture_tgt(${TNAME})
|
||||
endif ()
|
||||
endfunction (add_lcov_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Search for required lcov binaries.
|
||||
find_program(LCOV_BIN lcov)
|
||||
find_program(GENINFO_BIN geninfo)
|
||||
find_program(GENHTML_BIN genhtml)
|
||||
find_package_handle_standard_args(lcov
|
||||
REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN
|
||||
)
|
||||
|
||||
# enable genhtml C++ demangeling, if c++filt is found.
|
||||
set(GENHTML_CPPFILT_FLAG "")
|
||||
find_program(CPPFILT_BIN c++filt)
|
||||
if (NOT CPPFILT_BIN STREQUAL "")
|
||||
set(GENHTML_CPPFILT_FLAG "--demangle-cpp")
|
||||
endif (NOT CPPFILT_BIN STREQUAL "")
|
||||
|
||||
# enable no-external flag for lcov, if available.
|
||||
if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG)
|
||||
set(FLAG "")
|
||||
execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP)
|
||||
string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}")
|
||||
if (GENINFO_RES)
|
||||
set(FLAG "--no-external")
|
||||
endif ()
|
||||
|
||||
set(GENINFO_EXTERN_FLAG "${FLAG}"
|
||||
CACHE STRING "Geninfo flag to exclude system sources.")
|
||||
endif ()
|
||||
|
||||
# If Lcov was not found, exit module now.
|
||||
if (NOT LCOV_FOUND)
|
||||
return()
|
||||
endif (NOT LCOV_FOUND)
|
||||
|
||||
|
||||
|
||||
|
||||
# Create directories to be used.
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT})
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE})
|
||||
|
||||
set(LCOV_REMOVE_PATTERNS "")
|
||||
|
||||
# This function will merge lcov files to a single target file. Additional lcov
|
||||
# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function.
|
||||
function (lcov_merge_files OUTFILE ...)
|
||||
# Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files.
|
||||
list(REMOVE_AT ARGV 0)
|
||||
|
||||
# Generate merged file.
|
||||
string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}")
|
||||
add_custom_command(OUTPUT "${OUTFILE}.raw"
|
||||
COMMAND cat ${ARGV} > ${OUTFILE}.raw
|
||||
DEPENDS ${ARGV}
|
||||
COMMENT "Generating ${FILE_REL}"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT "${OUTFILE}"
|
||||
COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE}
|
||||
--base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS}
|
||||
COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS}
|
||||
--output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS}
|
||||
DEPENDS ${OUTFILE}.raw
|
||||
COMMENT "Post-processing ${FILE_REL}"
|
||||
)
|
||||
endfunction ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate initial coverage reports for all targets.
|
||||
# This target will be used to generate the global initial info file, which is
|
||||
# used to gather even empty report data.
|
||||
if (NOT TARGET lcov-capture-init)
|
||||
add_custom_target(lcov-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture-init)
|
||||
|
||||
|
||||
# This function will add initial capture of coverage data for target <TNAME>,
|
||||
# which is needed to get also data for objects, which were not loaded at
|
||||
# execution time. It will call geninfo for every source file of <TNAME> once and
|
||||
# store the info file in the same directory.
|
||||
function (lcov_capture_initial_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# generate empty coverage files
|
||||
set(OUTFILE "${TDIR}/${FILE}.info.init")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN}
|
||||
--quiet --base-directory ${PROJECT_SOURCE_DIR} --initial
|
||||
--gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE}
|
||||
${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno
|
||||
DEPENDS ${TNAME}
|
||||
COMMENT "Capturing initial coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info")
|
||||
set(LCOV_EXTRA_FLAGS "--initial")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-geninfo target
|
||||
add_dependencies(lcov-capture-init ${TNAME}-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}"
|
||||
"${OUTFILE}" CACHE INTERNAL ""
|
||||
)
|
||||
endfunction (lcov_capture_initial_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture_initial)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES})
|
||||
add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE}
|
||||
lcov-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_initial)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate coverage reports for all targets. This
|
||||
# target will be used to generate the global info file.
|
||||
if (NOT TARGET lcov-capture)
|
||||
add_custom_target(lcov-capture)
|
||||
set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture)
|
||||
|
||||
|
||||
# This function will add capture of coverage data for target <TNAME>, which is
|
||||
# needed to get also data for objects, which were not loaded at execution time.
|
||||
# It will call geninfo for every source file of <TNAME> once and store the info
|
||||
# file in the same directory.
|
||||
function (lcov_capture_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# Generate coverage files. If no .gcda file was generated during
|
||||
# execution, the empty coverage file will be used instead.
|
||||
set(OUTFILE "${TDIR}/${FILE}.info")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE}
|
||||
COMMAND test -f "${TDIR}/${FILE}.gcda"
|
||||
&& ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory
|
||||
${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN}
|
||||
--output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG}
|
||||
${TDIR}/${FILE}.gcda
|
||||
|| cp ${OUTFILE}.init ${OUTFILE}
|
||||
DEPENDS ${TNAME} ${TNAME}-capture-init
|
||||
COMMENT "Capturing coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-capture target
|
||||
add_dependencies(lcov-capture ${TNAME}-geninfo)
|
||||
set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL
|
||||
""
|
||||
)
|
||||
|
||||
# Add target for generating html output for this target only.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME})
|
||||
add_custom_target(${TNAME}-genhtml
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR}
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info
|
||||
--output-directory ${LCOV_HTML_PATH}/${TNAME}
|
||||
--title "${CMAKE_PROJECT_NAME} - target ${TNAME}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES})
|
||||
add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture)
|
||||
|
||||
# Add a new global target for all lcov targets. This target could be used to
|
||||
# generate the lcov html output for the whole project instead of calling
|
||||
# <TARGET>-geninfo and <TARGET>-genhtml for each target. It will also be
|
||||
# used to generate a html site for all project data together instead of one
|
||||
# for each target.
|
||||
if (NOT TARGET lcov)
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets)
|
||||
add_custom_target(lcov
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info
|
||||
--output-directory ${LCOV_HTML_PATH}/all_targets
|
||||
--title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS lcov-geninfo-init lcov-geninfo
|
||||
)
|
||||
endif ()
|
||||
endfunction (lcov_capture)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate the lcov html report for the whole project
|
||||
# instead of calling <TARGET>-genhtml for each target (to create an own report
|
||||
# for each target). Instead of the lcov target it does not require geninfo for
|
||||
# all targets, so you have to call <TARGET>-geninfo to generate the info files
|
||||
# the targets you'd like to have in your report or lcov-geninfo for generating
|
||||
# info files for all targets before calling lcov-genhtml.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets)
|
||||
if (NOT TARGET lcov-genhtml)
|
||||
add_custom_target(lcov-genhtml
|
||||
COMMAND ${GENHTML_BIN}
|
||||
--quiet
|
||||
--output-directory ${LCOV_HTML_PATH}/selected_targets
|
||||
--title \"${CMAKE_PROJECT_NAME} - targets `find
|
||||
${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\" -exec basename {} .info \\\;`\"
|
||||
--prefix ${PROJECT_SOURCE_DIR}
|
||||
--sort
|
||||
${GENHTML_CPPFILT_FLAG}
|
||||
`find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\"`
|
||||
)
|
||||
endif (NOT TARGET lcov-genhtml)
|
||||
@@ -1,258 +0,0 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# Add an option to choose, if coverage should be enabled or not. If enabled
|
||||
# marked targets will be build with coverage support and appropriate targets
|
||||
# will be added. If disabled coverage will be ignored for *ALL* targets.
|
||||
option(ENABLE_COVERAGE "Enable coverage build." OFF)
|
||||
|
||||
set(COVERAGE_FLAG_CANDIDATES
|
||||
# gcc and clang
|
||||
"-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
|
||||
# gcc and clang fallback
|
||||
"-O0 -g --coverage"
|
||||
)
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation. If coverage is disabled or not supported, this function will
|
||||
# simply do nothing.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_coverage TNAME)
|
||||
# only add coverage for target, if coverage is support and enabled.
|
||||
if (ENABLE_COVERAGE)
|
||||
foreach (TNAME ${ARGV})
|
||||
add_coverage_target(${TNAME})
|
||||
endforeach ()
|
||||
endif ()
|
||||
endfunction (add_coverage)
|
||||
|
||||
|
||||
# Add global target to gather coverage information after all targets have been
|
||||
# added. Other evaluation functions could be added here, after checks for the
|
||||
# specific module have been passed.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (coverage_evaluate)
|
||||
# add lcov evaluation
|
||||
if (LCOV_FOUND)
|
||||
lcov_capture_initial()
|
||||
lcov_capture()
|
||||
endif (LCOV_FOUND)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Exit this module, if coverage is disabled. add_coverage is defined before this
|
||||
# return, so this module can be exited now safely without breaking any build-
|
||||
# scripts.
|
||||
if (NOT ENABLE_COVERAGE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Find the reuired flags foreach language.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Coverage flags are not dependent on language, but the used compiler. So
|
||||
# instead of searching flags foreach language, search flags foreach compiler
|
||||
# used.
|
||||
set(COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
if (NOT COVERAGE_${COMPILER}_FLAGS)
|
||||
foreach (FLAG ${COVERAGE_FLAG_CANDIDATES})
|
||||
if(NOT CMAKE_REQUIRED_QUIET)
|
||||
message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
|
||||
unset(COVERAGE_FLAG_DETECTED CACHE)
|
||||
|
||||
if (${LANG} STREQUAL "C")
|
||||
include(CheckCCompilerFlag)
|
||||
check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "CXX")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "Fortran")
|
||||
# CheckFortranCompilerFlag was introduced in CMake 3.x. To be
|
||||
# compatible with older Cmake versions, we will check if this
|
||||
# module is present before we use it. Otherwise we will define
|
||||
# Fortran coverage support as not available.
|
||||
include(CheckFortranCompilerFlag OPTIONAL
|
||||
RESULT_VARIABLE INCLUDED)
|
||||
if (INCLUDED)
|
||||
check_fortran_compiler_flag("${FLAG}"
|
||||
COVERAGE_FLAG_DETECTED)
|
||||
elseif (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED")
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed"
|
||||
" (Check not supported)")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (COVERAGE_FLAG_DETECTED)
|
||||
set(COVERAGE_${COMPILER}_FLAGS "${FLAG}"
|
||||
CACHE STRING "${COMPILER} flags for code coverage.")
|
||||
mark_as_advanced(COVERAGE_${COMPILER}_FLAGS)
|
||||
break()
|
||||
else ()
|
||||
message(WARNING "Code coverage is not available for ${COMPILER}"
|
||||
" compiler. Targets using this compiler will be "
|
||||
"compiled without it.")
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
|
||||
|
||||
|
||||
|
||||
|
||||
# Helper function to get the language of a source file.
|
||||
function (codecov_lang_of_source FILE RETURN_VAR)
|
||||
get_filename_component(FILE_EXT "${FILE}" EXT)
|
||||
string(TOLOWER "${FILE_EXT}" FILE_EXT)
|
||||
string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT)
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP)
|
||||
if (NOT ${TEMP} EQUAL -1)
|
||||
set(${RETURN_VAR} "${LANG}" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Helper function to get the relative path of the source file destination path.
|
||||
# This path is needed by FindGcov and FindLcov cmake files to locate the
|
||||
# captured data.
|
||||
function (codecov_path_of_source FILE RETURN_VAR)
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE})
|
||||
|
||||
# If expression was found, SOURCEFILE is a generator-expression for an
|
||||
# object library. Currently we found no way to call this function automatic
|
||||
# for the referenced target, so it must be called in the directoryso of the
|
||||
# object library definition.
|
||||
if (NOT "${_source}" STREQUAL "")
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}")
|
||||
if(IS_ABSOLUTE ${FILE})
|
||||
file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE})
|
||||
endif()
|
||||
|
||||
# get the right path for file
|
||||
string(REPLACE ".." "__" PATH "${FILE}")
|
||||
|
||||
set(${RETURN_VAR} "${PATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation.
|
||||
function(add_coverage_target TNAME)
|
||||
# Check if all sources for target use the same compiler. If a target uses
|
||||
# e.g. C and Fortran mixed and uses different compilers (e.g. clang and
|
||||
# gfortran) this can trigger huge problems, because different compilers may
|
||||
# use different implementations for code coverage.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(TARGET_COMPILER "")
|
||||
set(ADDITIONAL_FILES "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
# If expression was found, FILE is a generator-expression for an object
|
||||
# library. Object libraries will be ignored.
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE})
|
||||
if ("${_file}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (LANG)
|
||||
list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcno")
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcda")
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
list(REMOVE_DUPLICATES TARGET_COMPILER)
|
||||
list(LENGTH TARGET_COMPILER NUM_COMPILERS)
|
||||
|
||||
if (NUM_COMPILERS GREATER 1)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it will be compiled by incompatible compilers. Target will be "
|
||||
"compiled without code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NUM_COMPILERS EQUAL 0)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it uses an unknown compiler. Target will be compiled without "
|
||||
"code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS")
|
||||
# A warning has been printed before, so just return if flags for this
|
||||
# compiler aren't available.
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# enable coverage for target
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
|
||||
|
||||
# Add gcov files generated by compiler to clean target.
|
||||
set(CLEAN_FILES "")
|
||||
foreach (FILE ${ADDITIONAL_FILES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}")
|
||||
endforeach()
|
||||
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${CLEAN_FILES}")
|
||||
|
||||
|
||||
add_gcov_target(${TNAME})
|
||||
add_lcov_target(${TNAME})
|
||||
endfunction(add_coverage_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# Include modules for parsing the collected data and output it in a readable
|
||||
# format (like gcov and lcov).
|
||||
find_package(Gcov)
|
||||
find_package(Lcov)
|
||||
@@ -1,79 +0,0 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
function(add_cxx_flag_if_supported_to_targets flagname targets)
|
||||
check_cxx_compiler_flag("${flagname}" HAVE_FLAG_${flagname})
|
||||
|
||||
if (HAVE_FLAG_${flagname})
|
||||
foreach(target ${targets})
|
||||
target_compile_options(${target} PUBLIC ${flagname})
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Assumes that it is only called for development builds, where warnings
|
||||
# and Werror is desired, so it also enables Werror.
|
||||
function(add_warnings_to_targets targets)
|
||||
LIST(LENGTH targets TARGETS_LEN)
|
||||
# For now we just assume 2 possibilities: msvc and msvc-like compilers,
|
||||
# and other.
|
||||
if (MSVC)
|
||||
foreach(target ${targets})
|
||||
# Force MSVC to consider everything as encoded in utf-8
|
||||
target_compile_options( ${target} PRIVATE /utf-8 )
|
||||
# Enable Werror equivalent
|
||||
if (CATCH_ENABLE_WERROR)
|
||||
target_compile_options( ${target} PRIVATE /WX )
|
||||
endif()
|
||||
|
||||
# MSVC is currently handled specially
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
|
||||
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
|
||||
target_compile_options( ${target} PRIVATE /w44265 /w44061 /w44062 /w45038 )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
set(CHECKED_WARNING_FLAGS
|
||||
"-Wall"
|
||||
"-Wextra"
|
||||
"-Wpedantic"
|
||||
"-Wweak-vtables"
|
||||
"-Wunreachable-code"
|
||||
"-Wmissing-declarations"
|
||||
"-Wexit-time-destructors"
|
||||
"-Wglobal-constructors"
|
||||
"-Wmissing-noreturn"
|
||||
"-Wparentheses"
|
||||
"-Wextra-semi-stmt"
|
||||
"-Wunreachable-code"
|
||||
"-Wstrict-aliasing"
|
||||
"-Wreturn-std-move"
|
||||
"-Wmissing-braces"
|
||||
"-Wdeprecated"
|
||||
"-Wvla"
|
||||
"-Wundef"
|
||||
"-Wmisleading-indentation"
|
||||
"-Wcatch-value"
|
||||
"-Wabsolute-value"
|
||||
"-Wreturn-std-move"
|
||||
"-Wunused-parameter"
|
||||
"-Wunused-function"
|
||||
"-Wcall-to-pure-virtual-from-ctor-dtor"
|
||||
"-Wdeprecated-register"
|
||||
"-Wsuggest-override"
|
||||
"-Wshadow"
|
||||
"-Wold-style-cast"
|
||||
)
|
||||
foreach(warning ${CHECKED_WARNING_FLAGS})
|
||||
add_cxx_flag_if_supported_to_targets(${warning} "${targets}")
|
||||
endforeach()
|
||||
|
||||
if (CATCH_ENABLE_WERROR)
|
||||
foreach(target ${targets})
|
||||
# Enable Werror equivalent
|
||||
target_compile_options( ${target} PRIVATE -Werror )
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,10 +0,0 @@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
pkg_version=@Catch2_VERSION@
|
||||
|
||||
Name: Catch2-With-Main
|
||||
Description: A modern, C++-native test framework for C++14 and above (links in default main)
|
||||
Version: ${pkg_version}
|
||||
Requires: catch2 = ${pkg_version}
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lCatch2WithMain
|
||||
@@ -1,9 +0,0 @@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
|
||||
Name: Catch2
|
||||
Description: A modern, C++-native, test framework for C++14 and above
|
||||
URL: https://github.com/catchorg/Catch2
|
||||
Version: @Catch2_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lCatch2
|
||||
@@ -1,56 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
if [ -z "$LLVM_COV_BIN" ]
|
||||
then
|
||||
echo "LLVM_COV_BIN not set!" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Get LLVM version to find out.
|
||||
LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \
|
||||
| sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g")
|
||||
|
||||
if [ "$1" = "-v" ]
|
||||
then
|
||||
echo "llvm-cov-wrapper $LLVM_VERSION"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$LLVM_VERSION" ]
|
||||
then
|
||||
MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1)
|
||||
MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2)
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ]
|
||||
then
|
||||
if [ -f "$1" ]
|
||||
then
|
||||
filename=$(basename "$1")
|
||||
extension="${filename##*.}"
|
||||
|
||||
case "$extension" in
|
||||
"gcno") exec $LLVM_COV_BIN --gcno="$1" ;;
|
||||
"gcda") exec $LLVM_COV_BIN --gcda="$1" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ]
|
||||
then
|
||||
exec $LLVM_COV_BIN $@
|
||||
fi
|
||||
fi
|
||||
|
||||
exec $LLVM_COV_BIN gcov $@
|
||||
@@ -1,208 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# detect if Catch is being bundled,
|
||||
# disable testsuite in that case
|
||||
if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
|
||||
option(CATCH_INSTALL_EXTRAS "Install extras alongside library" ON)
|
||||
option(CATCH_DEVELOPMENT_BUILD "Build tests, enable warnings, enable Werror, etc" OFF)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
cmake_dependent_option(CATCH_BUILD_TESTING "Build the SelfTest project" ON "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_EXAMPLES "Build code examples" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_FUZZERS "Build fuzzers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
|
||||
|
||||
# Catch2's build breaks if done in-tree. You probably should not build
|
||||
# things in tree anyway, but we can allow projects that include Catch2
|
||||
# as a subproject to build in-tree as long as it is not in our tree.
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.8)
|
||||
# Enable IPO for CMake versions that support it
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
endif()
|
||||
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 3.0.0)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CTest)
|
||||
|
||||
# This variable is used in some subdirectories, so we need it here, rather
|
||||
# than later in the install block
|
||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||
|
||||
# We have some Windows builds that test `wmain` entry point,
|
||||
# and we need this change to be present in all binaries that
|
||||
# are built during these tests, so this is required here, before
|
||||
# the subdirectories are added.
|
||||
if(CATCH_TEST_USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
|
||||
|
||||
# Basic paths
|
||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SOURCES_DIR ${CATCH_DIR}/src/catch2)
|
||||
set(SELF_TEST_DIR ${CATCH_DIR}/tests/SelfTest)
|
||||
set(BENCHMARK_DIR ${CATCH_DIR}/tests/Benchmark)
|
||||
set(EXAMPLES_DIR ${CATCH_DIR}/examples)
|
||||
|
||||
# We need to bring-in the variables defined there to this scope
|
||||
add_subdirectory(src)
|
||||
|
||||
# Build tests only if requested
|
||||
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||
find_package(PythonInterp 3 REQUIRED)
|
||||
if (NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR "Python not found, but required for tests")
|
||||
endif()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_EXTRA_TESTS)
|
||||
add_subdirectory(tests/ExtraTests)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_FUZZERS)
|
||||
add_subdirectory(fuzzing)
|
||||
endif()
|
||||
|
||||
if (CATCH_DEVELOPMENT_BUILD)
|
||||
add_warnings_to_targets("${CATCH_WARNING_TARGETS}")
|
||||
endif()
|
||||
|
||||
|
||||
#option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
|
||||
#option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
|
||||
#
|
||||
#set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# Only perform the installation steps when Catch is not being used as
|
||||
# a subproject via `add_subdirectory`, or the destinations will break,
|
||||
# see https://github.com/catchorg/Catch2/issues/1373
|
||||
if (NOT_SUBPROJECT)
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
|
||||
INSTALL_DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
## TODO: Catch2 main target?
|
||||
## Install some cpp file as well?
|
||||
|
||||
# By default, FooConfigVersion is tied to architecture that it was
|
||||
# generated on. Because Catch2 is header-only, it is arch-independent
|
||||
# and thus Catch2ConfigVersion should not be tied to the architecture
|
||||
# it was generated on.
|
||||
#
|
||||
# CMake does not provide a direct customization point for this in
|
||||
# `write_basic_package_version_file`, but it can be accomplished
|
||||
# indirectly by temporarily redefining `CMAKE_SIZEOF_VOID_P` to an
|
||||
# empty string. Note that just undefining the variable could be
|
||||
# insufficient in cases where the variable was already in CMake cache
|
||||
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||
set(CMAKE_SIZEOF_VOID_P "")
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
COMPATIBILITY
|
||||
SameMajorVersion
|
||||
)
|
||||
set(CMAKE_SIZEOF_VOID_P ${CATCH2_CMAKE_SIZEOF_VOID_P})
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
# Install documentation
|
||||
if(CATCH_INSTALL_DOCS)
|
||||
install(
|
||||
DIRECTORY
|
||||
docs/
|
||||
DESTINATION
|
||||
"${CMAKE_INSTALL_DOCDIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CATCH_INSTALL_EXTRAS)
|
||||
# Install CMake scripts
|
||||
install(
|
||||
FILES
|
||||
"extras/ParseAndAddCatchTests.cmake"
|
||||
"extras/Catch.cmake"
|
||||
"extras/CatchAddTests.cmake"
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
# Install debugger helpers
|
||||
install(
|
||||
FILES
|
||||
"extras/gdbinit"
|
||||
"extras/lldbinit"
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
|
||||
)
|
||||
endif()
|
||||
|
||||
## Provide some pkg-config integration
|
||||
set(PKGCONFIG_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||
CACHE PATH "Path where catch2.pc is installed"
|
||||
)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
|
||||
@ONLY
|
||||
)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2-with-main.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/catch2-with-main.pc
|
||||
@ONLY
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/catch2-with-main.pc"
|
||||
DESTINATION
|
||||
${PKGCONFIG_INSTALL_DIR}
|
||||
)
|
||||
|
||||
# CPack/CMake started taking the package version from project version 3.12
|
||||
# So we need to set the version manually for older CMake versions
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
|
||||
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_CONTACT "https://github.com/catchorg/Catch2/")
|
||||
|
||||
|
||||
include( CPack )
|
||||
|
||||
endif(NOT_SUBPROJECT)
|
||||
@@ -1,39 +1,28 @@
|
||||
<a id="top"></a>
|
||||

|
||||

|
||||
|
||||
[](https://github.com/catchorg/catch2/releases)
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://godbolt.org/z/9x9qoM)
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/6JUH8Eybx4CtvkJS)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
## Catch2 v3 is being developed!
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.13.10/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
You are on the `devel` branch, where the next major version, v3, of
|
||||
Catch2 is being developed. As it is a significant rework, you will
|
||||
find that parts of this documentation are likely still stuck on v2.
|
||||
## Catch2 is released!
|
||||
|
||||
For stable (and documentation-matching) version of Catch2, [go to the
|
||||
`v2.x` branch](https://github.com/catchorg/Catch2/tree/v2.x).
|
||||
If you've been using an earlier version of Catch, please see the
|
||||
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
|
||||
before moving to Catch2. You might also like to read [this blog post](https://levelofindirection.com/blog/catch2-released.html) for more details.
|
||||
|
||||
For migrating from the v2 releases to v3, you should look at [our
|
||||
documentation](docs/migrate-v2-to-v3.md#top). It provides a simple
|
||||
guidelines on getting started, and collects most common migration
|
||||
problems.
|
||||
|
||||
|
||||
## What's the Catch2?
|
||||
|
||||
Catch2 is mainly a unit testing framework for C++, but it also
|
||||
provides basic micro-benchmarking features, and simple BDD macros.
|
||||
|
||||
Catch2's main advantage is that using it is both simple and natural.
|
||||
Tests autoregister themselves and do not have to be named with valid
|
||||
identifiers, assertions look like normal C++ code, and sections provide
|
||||
a nice way to share set-up and tear-down code in tests.
|
||||
## What's the Catch?
|
||||
|
||||
Catch2 is a multi-paradigm test framework for C++. which also supports
|
||||
Objective-C (and maybe C).
|
||||
It is primarily distributed as a single header file, although certain
|
||||
extensions may require additional headers.
|
||||
|
||||
## How to use it
|
||||
This documentation comprises these three parts:
|
||||
@@ -42,7 +31,6 @@ This documentation comprises these three parts:
|
||||
* [Tutorial](docs/tutorial.md#top) - getting started
|
||||
* [Reference section](docs/Readme.md#top) - all the details
|
||||
|
||||
|
||||
## More
|
||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
||||
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD)
|
||||
|
||||
@@ -202,4 +202,5 @@ endfunction()
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
|
||||
)
|
||||
@@ -16,7 +16,10 @@ set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
|
||||
math(EXPR _last_arg ${ARGC}-1)
|
||||
foreach(_n RANGE 1 ${_last_arg})
|
||||
set(_arg "${ARGV${_n}}")
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
@@ -33,12 +36,17 @@ if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests --verbosity quiet
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${result} EQUAL 0)
|
||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||
)
|
||||
elseif(${result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
@@ -55,7 +63,11 @@ execute_process(
|
||||
RESULT_VARIABLE reporters_result
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${reporters_result} EQUAL 0)
|
||||
if(${reporters_result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no reporters!\n"
|
||||
)
|
||||
elseif(${reporters_result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${reporters_result}\n"
|
||||
@@ -200,7 +200,7 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary,
|
||||
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
|
||||
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
|
||||
# And properly introduced in 3.19 with the CMP0110 policy
|
||||
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
|
||||
@@ -241,6 +241,7 @@ endfunction()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddCatchTests TestTarget)
|
||||
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
@@ -1,368 +0,0 @@
|
||||
include(MiscFunctions)
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(BENCHMARK_HEADERS
|
||||
${SOURCES_DIR}/benchmark/catch_benchmark.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_benchmark_all.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_chronometer.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_clock.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_constructor.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_environment.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_estimate.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_execution_plan.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_optimizer.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_outlier_classification.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_sample_analysis.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_analyse.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_complete_invoke.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_estimate_clock.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_measure.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_repeat.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_run_for_at_least.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_stats.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_timing.hpp
|
||||
)
|
||||
set(BENCHMARK_SOURCES
|
||||
${SOURCES_DIR}/benchmark/internal/catch_benchmark_combined_tu.cpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_stats.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
|
||||
|
||||
set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/catch_all.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_all.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_all.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_all.hpp
|
||||
${SOURCES_DIR}/matchers/internal/catch_matchers_impl.hpp
|
||||
${SOURCES_DIR}/internal/catch_console_width.hpp
|
||||
${SOURCES_DIR}/internal/catch_container_nonmembers.hpp
|
||||
${SOURCES_DIR}/internal/catch_noncopyable.hpp
|
||||
${SOURCES_DIR}/catch_approx.hpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.hpp
|
||||
${SOURCES_DIR}/catch_assertion_info.hpp
|
||||
${SOURCES_DIR}/catch_assertion_result.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_macro_impl.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_failure_exception.hpp
|
||||
${SOURCES_DIR}/internal/catch_case_sensitive.hpp
|
||||
${SOURCES_DIR}/internal/catch_clara.hpp
|
||||
${SOURCES_DIR}/internal/catch_commandline.hpp
|
||||
${SOURCES_DIR}/internal/catch_source_line_info.hpp
|
||||
${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp
|
||||
${SOURCES_DIR}/catch_config.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_counter.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_uncaught_exceptions.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_wchar.hpp
|
||||
${SOURCES_DIR}/internal/catch_console_colour.hpp
|
||||
${SOURCES_DIR}/internal/catch_context.hpp
|
||||
${SOURCES_DIR}/internal/catch_debug_console.hpp
|
||||
${SOURCES_DIR}/internal/catch_debugger.hpp
|
||||
${SOURCES_DIR}/internal/catch_decomposer.hpp
|
||||
${SOURCES_DIR}/internal/catch_enforce.hpp
|
||||
${SOURCES_DIR}/internal/catch_enum_values_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_errno_guard.hpp
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_name.hpp
|
||||
${SOURCES_DIR}/generators/catch_generator_exception.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_adapters.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_random.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_range.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_capture.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_config.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_enum_values_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_exception.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_runner.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_tag_alias_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp
|
||||
${SOURCES_DIR}/internal/catch_lazy_expr.hpp
|
||||
${SOURCES_DIR}/internal/catch_leak_detector.hpp
|
||||
${SOURCES_DIR}/internal/catch_list.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_contains.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_quantifiers.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_vector.hpp
|
||||
${SOURCES_DIR}/catch_message.hpp
|
||||
${SOURCES_DIR}/internal/catch_message_info.hpp
|
||||
${SOURCES_DIR}/internal/catch_meta.hpp
|
||||
${SOURCES_DIR}/internal/catch_option.hpp
|
||||
${SOURCES_DIR}/internal/catch_output_redirect.hpp
|
||||
${SOURCES_DIR}/internal/catch_platform.hpp
|
||||
${SOURCES_DIR}/internal/catch_polyfills.hpp
|
||||
${SOURCES_DIR}/internal/catch_preprocessor.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.hpp
|
||||
${SOURCES_DIR}/catch_reporter_registrars.hpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_result_type.hpp
|
||||
${SOURCES_DIR}/internal/catch_run_context.hpp
|
||||
${SOURCES_DIR}/internal/catch_section.hpp
|
||||
${SOURCES_DIR}/catch_section_info.hpp
|
||||
${SOURCES_DIR}/catch_session.hpp
|
||||
${SOURCES_DIR}/internal/catch_singletons.hpp
|
||||
${SOURCES_DIR}/internal/catch_startup_exception_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_stream.hpp
|
||||
${SOURCES_DIR}/internal/catch_stream_end_stop.hpp
|
||||
${SOURCES_DIR}/internal/catch_string_manip.hpp
|
||||
${SOURCES_DIR}/internal/catch_stringref.hpp
|
||||
${SOURCES_DIR}/catch_tag_alias.hpp
|
||||
${SOURCES_DIR}/catch_tag_alias_autoregistrar.hpp
|
||||
${SOURCES_DIR}/internal/catch_tag_alias_registry.hpp
|
||||
${SOURCES_DIR}/catch_test_case_info.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_registry_impl.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_tracker.hpp
|
||||
${SOURCES_DIR}/catch_template_test_macros.hpp
|
||||
${SOURCES_DIR}/catch_test_macros.hpp
|
||||
${SOURCES_DIR}/internal/catch_template_test_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_registry.hpp
|
||||
${SOURCES_DIR}/catch_test_spec.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_spec_parser.hpp
|
||||
${SOURCES_DIR}/internal/catch_textflow.hpp
|
||||
${SOURCES_DIR}/catch_timer.hpp
|
||||
${SOURCES_DIR}/internal/catch_to_string.hpp
|
||||
${SOURCES_DIR}/catch_tostring.hpp
|
||||
${SOURCES_DIR}/catch_totals.hpp
|
||||
${SOURCES_DIR}/catch_translate_exception.hpp
|
||||
${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_ptr.hpp
|
||||
${SOURCES_DIR}/catch_version.hpp
|
||||
${SOURCES_DIR}/catch_version_macros.hpp
|
||||
${SOURCES_DIR}/internal/catch_wildcard_pattern.hpp
|
||||
${SOURCES_DIR}/internal/catch_windows_h_proxy.hpp
|
||||
${SOURCES_DIR}/internal/catch_xmlwriter.hpp
|
||||
)
|
||||
set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_approx.cpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.cpp
|
||||
${SOURCES_DIR}/catch_assertion_result.cpp
|
||||
${SOURCES_DIR}/matchers/internal/catch_matchers_combined_tu.cpp
|
||||
${SOURCES_DIR}/internal/catch_clara.cpp
|
||||
${SOURCES_DIR}/internal/catch_commandline.cpp
|
||||
${SOURCES_DIR}/internal/catch_source_line_info.cpp
|
||||
${SOURCES_DIR}/catch_config.cpp
|
||||
${SOURCES_DIR}/internal/catch_console_colour.cpp
|
||||
${SOURCES_DIR}/internal/catch_context.cpp
|
||||
${SOURCES_DIR}/internal/catch_debug_console.cpp
|
||||
${SOURCES_DIR}/internal/catch_debugger.cpp
|
||||
${SOURCES_DIR}/internal/catch_enforce.cpp
|
||||
${SOURCES_DIR}/internal/catch_enum_values_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.cpp
|
||||
${SOURCES_DIR}/generators/internal/catch_generators_combined_tu.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_combined_tu.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
||||
${SOURCES_DIR}/internal/catch_list.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.cpp
|
||||
${SOURCES_DIR}/catch_message.cpp
|
||||
${SOURCES_DIR}/internal/catch_output_redirect.cpp
|
||||
${SOURCES_DIR}/catch_registry_hub.cpp
|
||||
${SOURCES_DIR}/internal/catch_combined_tu.cpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.cpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_result_type.cpp
|
||||
${SOURCES_DIR}/internal/catch_run_context.cpp
|
||||
${SOURCES_DIR}/internal/catch_section.cpp
|
||||
${SOURCES_DIR}/catch_session.cpp
|
||||
${SOURCES_DIR}/internal/catch_singletons.cpp
|
||||
${SOURCES_DIR}/internal/catch_stream.cpp
|
||||
${SOURCES_DIR}/internal/catch_stringref.cpp
|
||||
${SOURCES_DIR}/internal/catch_string_manip.cpp
|
||||
${SOURCES_DIR}/internal/catch_tag_alias_registry.cpp
|
||||
${SOURCES_DIR}/catch_test_case_info.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_registry_impl.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_tracker.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_textflow.cpp
|
||||
${SOURCES_DIR}/catch_test_spec.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_spec_parser.cpp
|
||||
${SOURCES_DIR}/catch_timer.cpp
|
||||
${SOURCES_DIR}/catch_tostring.cpp
|
||||
${SOURCES_DIR}/catch_totals.cpp
|
||||
${SOURCES_DIR}/catch_version.cpp
|
||||
${SOURCES_DIR}/internal/catch_wildcard_pattern.cpp
|
||||
${SOURCES_DIR}/internal/catch_xmlwriter.cpp
|
||||
)
|
||||
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(REPORTER_HEADERS
|
||||
${SOURCES_DIR}/reporters/catch_reporters_all.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_automake.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_compact.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_console.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_event_listener.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_helpers.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_junit.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_listening.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_sonarqube.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_streaming_base.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_tap.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_xml.hpp
|
||||
)
|
||||
set(REPORTER_SOURCES
|
||||
${SOURCES_DIR}/reporters/catch_reporter_automake.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_combined_tu.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_compact.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_console.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_junit.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_listening.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_sonarqube.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_streaming_base.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_tap.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_teamcity.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_xml.cpp
|
||||
)
|
||||
set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
|
||||
|
||||
# Fixme: STATIC because for dynamic, we would need to handle visibility
|
||||
# and I don't want to do the annotations right now
|
||||
add_library(Catch2 STATIC
|
||||
${REPORTER_FILES}
|
||||
${INTERNAL_FILES}
|
||||
${BENCHMARK_HEADERS}
|
||||
${BENCHMARK_SOURCES}
|
||||
)
|
||||
add_library(Catch2::Catch2 ALIAS Catch2)
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(Catch2 INTERFACE log)
|
||||
endif()
|
||||
|
||||
# depend on bunch of C++11 and C++14 features to have C++14 enabled by default
|
||||
target_compile_features(Catch2
|
||||
PUBLIC
|
||||
cxx_alignas
|
||||
cxx_alignof
|
||||
cxx_attributes
|
||||
cxx_auto_type
|
||||
cxx_constexpr
|
||||
cxx_defaulted_functions
|
||||
cxx_deleted_functions
|
||||
cxx_final
|
||||
cxx_lambdas
|
||||
cxx_noexcept
|
||||
cxx_override
|
||||
cxx_range_for
|
||||
cxx_rvalue_references
|
||||
cxx_static_assert
|
||||
cxx_strong_enums
|
||||
cxx_trailing_return_types
|
||||
cxx_unicode_literals
|
||||
cxx_user_literals
|
||||
cxx_variable_templates
|
||||
cxx_variadic_macros
|
||||
)
|
||||
|
||||
if (NOT_SUBPROJECT)
|
||||
target_include_directories(Catch2
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
else()
|
||||
target_include_directories(Catch2
|
||||
SYSTEM PUBLIC
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
add_library(Catch2WithMain STATIC
|
||||
${SOURCES_DIR}/internal/catch_main.cpp
|
||||
)
|
||||
add_library(Catch2::Catch2WithMain ALIAS Catch2WithMain)
|
||||
target_link_libraries(Catch2WithMain PUBLIC Catch2)
|
||||
set_target_properties(Catch2WithMain
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "Catch2Main"
|
||||
)
|
||||
|
||||
if (NOT_SUBPROJECT)
|
||||
# create and install an export set for catch target as Catch2::Catch
|
||||
install(
|
||||
TARGETS
|
||||
Catch2
|
||||
Catch2WithMain
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
|
||||
install(
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
NAMESPACE
|
||||
Catch2::
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
# Install the headers
|
||||
install(DIRECTORY ${SOURCES_DIR} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h*")
|
||||
endif()
|
||||
|
||||
# Some tests require a full recompilation of Catch2 lib with different
|
||||
# compilation flags. They can link against this target to recompile all
|
||||
# the sources into the binary.
|
||||
if (CATCH_BUILD_EXAMPLES OR CATCH_BUILD_EXTRA_TESTS)
|
||||
add_library(Catch2_buildall_interface INTERFACE)
|
||||
target_sources(Catch2_buildall_interface INTERFACE
|
||||
${REPORTER_FILES}
|
||||
${INTERNAL_FILES}
|
||||
${BENCHMARK_HEADERS}
|
||||
${BENCHMARK_SOURCES}
|
||||
# Also include main entry point
|
||||
${SOURCES_DIR}/internal/catch_main.cpp
|
||||
)
|
||||
target_include_directories(Catch2_buildall_interface
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_features(Catch2_buildall_interface
|
||||
INTERFACE
|
||||
cxx_alignas
|
||||
cxx_alignof
|
||||
cxx_attributes
|
||||
cxx_auto_type
|
||||
cxx_constexpr
|
||||
cxx_defaulted_functions
|
||||
cxx_deleted_functions
|
||||
cxx_final
|
||||
cxx_lambdas
|
||||
cxx_noexcept
|
||||
cxx_override
|
||||
cxx_range_for
|
||||
cxx_rvalue_references
|
||||
cxx_static_assert
|
||||
cxx_strong_enums
|
||||
cxx_trailing_return_types
|
||||
cxx_unicode_literals
|
||||
cxx_user_literals
|
||||
cxx_variable_templates
|
||||
cxx_variadic_macros
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND CATCH_WARNING_TARGETS Catch2 Catch2WithMain)
|
||||
set(CATCH_WARNING_TARGETS ${CATCH_WARNING_TARGETS} PARENT_SCOPE)
|
||||
@@ -1,138 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_BENCHMARK_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct Benchmark {
|
||||
Benchmark(std::string&& benchmarkName)
|
||||
: name(std::move(benchmarkName)) {}
|
||||
|
||||
template <class FUN>
|
||||
Benchmark(std::string&& benchmarkName , FUN &&func)
|
||||
: fun(std::move(func)), name(std::move(benchmarkName)) {}
|
||||
|
||||
template <typename Clock>
|
||||
ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
||||
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
||||
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
||||
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
|
||||
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
||||
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
||||
}
|
||||
|
||||
template <typename Clock = default_clock>
|
||||
void run() {
|
||||
auto const* cfg = getCurrentContext().getConfig();
|
||||
|
||||
auto env = Detail::measure_environment<Clock>();
|
||||
|
||||
getResultCapture().benchmarkPreparing(name);
|
||||
CATCH_TRY{
|
||||
auto plan = user_code([&] {
|
||||
return prepare<Clock>(*cfg, env);
|
||||
});
|
||||
|
||||
BenchmarkInfo info {
|
||||
name,
|
||||
plan.estimated_duration.count(),
|
||||
plan.iterations_per_sample,
|
||||
cfg->benchmarkSamples(),
|
||||
cfg->benchmarkResamples(),
|
||||
env.clock_resolution.mean.count(),
|
||||
env.clock_cost.mean.count()
|
||||
};
|
||||
|
||||
getResultCapture().benchmarkStarting(info);
|
||||
|
||||
auto samples = user_code([&] {
|
||||
return plan.template run<Clock>(*cfg, env);
|
||||
});
|
||||
|
||||
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
||||
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
|
||||
} CATCH_CATCH_ALL{
|
||||
if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
// sets lambda to be used in fun *and* executes benchmark!
|
||||
template <typename Fun,
|
||||
typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
|
||||
Benchmark & operator=(Fun func) {
|
||||
fun = Detail::BenchmarkFunction(func);
|
||||
run();
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Detail::BenchmarkFunction fun;
|
||||
std::string name;
|
||||
};
|
||||
}
|
||||
} // namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
|
||||
#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
|
||||
|
||||
#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
|
||||
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||
BenchmarkName = [&](int benchmarkIndex)
|
||||
|
||||
#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
|
||||
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||
BenchmarkName = [&]
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_ALL)
|
||||
|
||||
#define CATCH_BENCHMARK(...) \
|
||||
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||
#define CATCH_BENCHMARK_ADVANCED(name) \
|
||||
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
|
||||
|
||||
#else
|
||||
|
||||
#define BENCHMARK(...) \
|
||||
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||
#define BENCHMARK_ADVANCED(name) \
|
||||
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CATCH_BENCHMARK_HPP_INCLUDED
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/** \file
|
||||
* This is a convenience header for Catch2's benchmarking. It includes
|
||||
* **all** of Catch2 headers related to benchmarking.
|
||||
*
|
||||
* Generally the Catch2 users should use specific includes they need,
|
||||
* but this header can be used instead for ease-of-experimentation, or
|
||||
* just plain convenience, at the cost of (significantly) increased
|
||||
* compilation times.
|
||||
*
|
||||
* When a new header is added to either the `benchmark` folder, or to
|
||||
* the corresponding internal (detail) subfolder, it should be added here.
|
||||
*/
|
||||
|
||||
#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_constructor.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
|
||||
#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
#define CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
struct ChronometerConcept {
|
||||
virtual void start() = 0;
|
||||
virtual void finish() = 0;
|
||||
virtual ~ChronometerConcept(); // = default;
|
||||
|
||||
ChronometerConcept() = default;
|
||||
ChronometerConcept(ChronometerConcept const&) = default;
|
||||
ChronometerConcept& operator=(ChronometerConcept const&) = default;
|
||||
};
|
||||
template <typename Clock>
|
||||
struct ChronometerModel final : public ChronometerConcept {
|
||||
void start() override { started = Clock::now(); }
|
||||
void finish() override { finished = Clock::now(); }
|
||||
|
||||
ClockDuration<Clock> elapsed() const { return finished - started; }
|
||||
|
||||
TimePoint<Clock> started;
|
||||
TimePoint<Clock> finished;
|
||||
};
|
||||
} // namespace Detail
|
||||
|
||||
struct Chronometer {
|
||||
public:
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
|
||||
|
||||
int runs() const { return repeats; }
|
||||
|
||||
Chronometer(Detail::ChronometerConcept& meter, int repeats_)
|
||||
: impl(&meter)
|
||||
, repeats(repeats_) {}
|
||||
|
||||
private:
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun, std::false_type) {
|
||||
measure([&fun](int) { return fun(); }, std::true_type());
|
||||
}
|
||||
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun, std::true_type) {
|
||||
Detail::optimizer_barrier();
|
||||
impl->start();
|
||||
for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
|
||||
impl->finish();
|
||||
Detail::optimizer_barrier();
|
||||
}
|
||||
|
||||
Detail::ChronometerConcept* impl;
|
||||
int repeats;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CLOCK_HPP_INCLUDED
|
||||
#define CATCH_CLOCK_HPP_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Clock>
|
||||
using ClockDuration = typename Clock::duration;
|
||||
template <typename Clock>
|
||||
using FloatDuration = std::chrono::duration<double, typename Clock::period>;
|
||||
|
||||
template <typename Clock>
|
||||
using TimePoint = typename Clock::time_point;
|
||||
|
||||
using default_clock = std::chrono::steady_clock;
|
||||
|
||||
template <typename Clock>
|
||||
struct now {
|
||||
TimePoint<Clock> operator()() const {
|
||||
return Clock::now();
|
||||
}
|
||||
};
|
||||
|
||||
using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CLOCK_HPP_INCLUDED
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
#define CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T, bool Destruct>
|
||||
struct ObjectStorage
|
||||
{
|
||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
||||
|
||||
ObjectStorage() : data() {}
|
||||
|
||||
ObjectStorage(const ObjectStorage& other)
|
||||
{
|
||||
new(&data) T(other.stored_object());
|
||||
}
|
||||
|
||||
ObjectStorage(ObjectStorage&& other)
|
||||
{
|
||||
new(&data) T(std::move(other.stored_object()));
|
||||
}
|
||||
|
||||
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||
|
||||
template <typename... Args>
|
||||
void construct(Args&&... args)
|
||||
{
|
||||
new (&data) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <bool AllowManualDestruction = !Destruct>
|
||||
typename std::enable_if<AllowManualDestruction>::type destruct()
|
||||
{
|
||||
stored_object().~T();
|
||||
}
|
||||
|
||||
private:
|
||||
// If this is a constructor benchmark, destruct the underlying object
|
||||
template <typename U>
|
||||
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
|
||||
// Otherwise, don't
|
||||
template <typename U>
|
||||
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
|
||||
|
||||
T& stored_object() {
|
||||
return *static_cast<T*>(static_cast<void*>(&data));
|
||||
}
|
||||
|
||||
T const& stored_object() const {
|
||||
return *static_cast<T*>(static_cast<void*>(&data));
|
||||
}
|
||||
|
||||
|
||||
TStorage data;
|
||||
};
|
||||
} // namespace Detail
|
||||
|
||||
template <typename T>
|
||||
using storage_for = Detail::ObjectStorage<T, true>;
|
||||
|
||||
template <typename T>
|
||||
using destructable_object = Detail::ObjectStorage<T, false>;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
#define CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Duration>
|
||||
struct EnvironmentEstimate {
|
||||
Duration mean;
|
||||
OutlierClassification outliers;
|
||||
|
||||
template <typename Duration2>
|
||||
operator EnvironmentEstimate<Duration2>() const {
|
||||
return { mean, outliers };
|
||||
}
|
||||
};
|
||||
template <typename Clock>
|
||||
struct Environment {
|
||||
using clock_type = Clock;
|
||||
EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
|
||||
EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ESTIMATE_HPP_INCLUDED
|
||||
#define CATCH_ESTIMATE_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Duration>
|
||||
struct Estimate {
|
||||
Duration point;
|
||||
Duration lower_bound;
|
||||
Duration upper_bound;
|
||||
double confidence_interval;
|
||||
|
||||
template <typename Duration2>
|
||||
operator Estimate<Duration2>() const {
|
||||
return { point, lower_bound, upper_bound, confidence_interval };
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ESTIMATE_HPP_INCLUDED
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Duration>
|
||||
struct ExecutionPlan {
|
||||
int iterations_per_sample;
|
||||
Duration estimated_duration;
|
||||
Detail::BenchmarkFunction benchmark;
|
||||
Duration warmup_time;
|
||||
int warmup_iterations;
|
||||
|
||||
template <typename Duration2>
|
||||
operator ExecutionPlan<Duration2>() const {
|
||||
return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
|
||||
}
|
||||
|
||||
template <typename Clock>
|
||||
std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
||||
// warmup a bit
|
||||
Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
|
||||
|
||||
std::vector<FloatDuration<Clock>> times;
|
||||
times.reserve(cfg.benchmarkSamples());
|
||||
std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
|
||||
Detail::ChronometerModel<Clock> model;
|
||||
this->benchmark(Chronometer(model, iterations_per_sample));
|
||||
auto sample_time = model.elapsed() - env.clock_cost.mean;
|
||||
if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
|
||||
return sample_time / iterations_per_sample;
|
||||
});
|
||||
return times;
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
@@ -1,70 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
#define CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <atomic> // atomic_thread_fence
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
template <typename T>
|
||||
inline void keep_memory(T* p) {
|
||||
asm volatile("" : : "g"(p) : "memory");
|
||||
}
|
||||
inline void keep_memory() {
|
||||
asm volatile("" : : : "memory");
|
||||
}
|
||||
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() { keep_memory(); }
|
||||
} // namespace Detail
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#pragma optimize("", off)
|
||||
template <typename T>
|
||||
inline void keep_memory(T* p) {
|
||||
// thanks @milleniumbug
|
||||
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
|
||||
}
|
||||
// TODO equivalent keep_memory()
|
||||
#pragma optimize("", on)
|
||||
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline void deoptimize_value(T&& x) {
|
||||
keep_memory(&x);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
|
||||
deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
|
||||
std::forward<Fn>(fn) (std::forward<Args...>(args...));
|
||||
}
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||
#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct OutlierClassification {
|
||||
int samples_seen = 0;
|
||||
int low_severe = 0; // more than 3 times IQR below Q1
|
||||
int low_mild = 0; // 1.5 to 3 times IQR below Q1
|
||||
int high_mild = 0; // 1.5 to 3 times IQR above Q3
|
||||
int high_severe = 0; // more than 3 times IQR above Q3
|
||||
|
||||
int total() const {
|
||||
return low_severe + low_mild + high_mild + high_severe;
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Duration>
|
||||
struct SampleAnalysis {
|
||||
std::vector<Duration> samples;
|
||||
Estimate<Duration> mean;
|
||||
Estimate<Duration> standard_deviation;
|
||||
OutlierClassification outliers;
|
||||
double outlier_variance;
|
||||
|
||||
template <typename Duration2>
|
||||
operator SampleAnalysis<Duration2>() const {
|
||||
std::vector<Duration2> samples2;
|
||||
samples2.reserve(samples.size());
|
||||
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
|
||||
return {
|
||||
std::move(samples2),
|
||||
mean,
|
||||
standard_deviation,
|
||||
outliers,
|
||||
outlier_variance,
|
||||
};
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ANALYSE_HPP_INCLUDED
|
||||
#define CATCH_ANALYSE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Duration, typename Iterator>
|
||||
SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
|
||||
if (!cfg.benchmarkNoAnalysis()) {
|
||||
std::vector<double> samples;
|
||||
samples.reserve(last - first);
|
||||
std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
|
||||
|
||||
auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
|
||||
auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
|
||||
|
||||
auto wrap_estimate = [](Estimate<double> e) {
|
||||
return Estimate<Duration> {
|
||||
Duration(e.point),
|
||||
Duration(e.lower_bound),
|
||||
Duration(e.upper_bound),
|
||||
e.confidence_interval,
|
||||
};
|
||||
};
|
||||
std::vector<Duration> samples2;
|
||||
samples2.reserve(samples.size());
|
||||
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
|
||||
return {
|
||||
std::move(samples2),
|
||||
wrap_estimate(analysis.mean),
|
||||
wrap_estimate(analysis.standard_deviation),
|
||||
outliers,
|
||||
analysis.outlier_variance,
|
||||
};
|
||||
} else {
|
||||
std::vector<Duration> samples;
|
||||
samples.reserve(last - first);
|
||||
|
||||
Duration mean = Duration(0);
|
||||
int i = 0;
|
||||
for (auto it = first; it < last; ++it, ++i) {
|
||||
samples.push_back(Duration(*it));
|
||||
mean += Duration(*it);
|
||||
}
|
||||
mean /= i;
|
||||
|
||||
return {
|
||||
std::move(samples),
|
||||
Estimate<Duration>{mean, mean, mean, 0.0},
|
||||
Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
|
||||
OutlierClassification{},
|
||||
0.0
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ANALYSE_HPP_INCLUDED
|
||||
@@ -1,109 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T>
|
||||
using Decay = typename std::decay<T>::type;
|
||||
template <typename T, typename U>
|
||||
struct is_related
|
||||
: std::is_same<Decay<T>, Decay<U>> {};
|
||||
|
||||
/// We need to reinvent std::function because every piece of code that might add overhead
|
||||
/// in a measurement context needs to have consistent performance characteristics so that we
|
||||
/// can account for it in the measurement.
|
||||
/// Implementations of std::function with optimizations that aren't always applicable, like
|
||||
/// small buffer optimizations, are not uncommon.
|
||||
/// This is effectively an implementation of std::function without any such optimizations;
|
||||
/// it may be slow, but it is consistently slow.
|
||||
struct BenchmarkFunction {
|
||||
private:
|
||||
struct callable {
|
||||
virtual void call(Chronometer meter) const = 0;
|
||||
virtual callable* clone() const = 0;
|
||||
virtual ~callable(); // = default;
|
||||
|
||||
callable() = default;
|
||||
callable(callable const&) = default;
|
||||
callable& operator=(callable const&) = default;
|
||||
};
|
||||
template <typename Fun>
|
||||
struct model : public callable {
|
||||
model(Fun&& fun_) : fun(std::move(fun_)) {}
|
||||
model(Fun const& fun_) : fun(fun_) {}
|
||||
|
||||
model<Fun>* clone() const override { return new model<Fun>(*this); }
|
||||
|
||||
void call(Chronometer meter) const override {
|
||||
call(meter, is_callable<Fun(Chronometer)>());
|
||||
}
|
||||
void call(Chronometer meter, std::true_type) const {
|
||||
fun(meter);
|
||||
}
|
||||
void call(Chronometer meter, std::false_type) const {
|
||||
meter.measure(fun);
|
||||
}
|
||||
|
||||
Fun fun;
|
||||
};
|
||||
|
||||
struct do_nothing { void operator()() const {} };
|
||||
|
||||
template <typename T>
|
||||
BenchmarkFunction(model<T>* c) : f(c) {}
|
||||
|
||||
public:
|
||||
BenchmarkFunction()
|
||||
: f(new model<do_nothing>{ {} }) {}
|
||||
|
||||
template <typename Fun,
|
||||
typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
|
||||
BenchmarkFunction(Fun&& fun)
|
||||
: f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
|
||||
|
||||
BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
|
||||
f( std::move( that.f ) ) {}
|
||||
|
||||
BenchmarkFunction(BenchmarkFunction const& that)
|
||||
: f(that.f->clone()) {}
|
||||
|
||||
BenchmarkFunction&
|
||||
operator=( BenchmarkFunction&& that ) noexcept {
|
||||
f = std::move( that.f );
|
||||
return *this;
|
||||
}
|
||||
|
||||
BenchmarkFunction& operator=(BenchmarkFunction const& that) {
|
||||
f.reset(that.f->clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(Chronometer meter) const { f->call(meter); }
|
||||
|
||||
private:
|
||||
Catch::Detail::unique_ptr<callable> f;
|
||||
};
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
@@ -1,69 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T>
|
||||
struct CompleteType { using type = T; };
|
||||
template <>
|
||||
struct CompleteType<void> { struct type {}; };
|
||||
|
||||
template <typename T>
|
||||
using CompleteType_t = typename CompleteType<T>::type;
|
||||
|
||||
template <typename Result>
|
||||
struct CompleteInvoker {
|
||||
template <typename Fun, typename... Args>
|
||||
static Result invoke(Fun&& fun, Args&&... args) {
|
||||
return std::forward<Fun>(fun)(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct CompleteInvoker<void> {
|
||||
template <typename Fun, typename... Args>
|
||||
static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
|
||||
std::forward<Fun>(fun)(std::forward<Args>(args)...);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// invoke and not return void :(
|
||||
template <typename Fun, typename... Args>
|
||||
CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
|
||||
return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
extern const std::string benchmarkErrorMsg;
|
||||
} // namespace Detail
|
||||
|
||||
template <typename Fun>
|
||||
Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
|
||||
CATCH_TRY{
|
||||
return Detail::complete_invoke(std::forward<Fun>(fun));
|
||||
} CATCH_CATCH_ALL{
|
||||
getResultCapture().benchmarkFailed(translateActiveException());
|
||||
CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
|
||||
}
|
||||
}
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
@@ -1,111 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock>
|
||||
std::vector<double> resolution(int k) {
|
||||
std::vector<TimePoint<Clock>> times;
|
||||
times.reserve(k + 1);
|
||||
std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
|
||||
|
||||
std::vector<double> deltas;
|
||||
deltas.reserve(k);
|
||||
std::transform(std::next(times.begin()), times.end(), times.begin(),
|
||||
std::back_inserter(deltas),
|
||||
[](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
|
||||
|
||||
return deltas;
|
||||
}
|
||||
|
||||
const auto warmup_iterations = 10000;
|
||||
const auto warmup_time = std::chrono::milliseconds(100);
|
||||
const auto minimum_ticks = 1000;
|
||||
const auto warmup_seed = 10000;
|
||||
const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
|
||||
const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
|
||||
const auto clock_cost_estimation_tick_limit = 100000;
|
||||
const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
|
||||
const auto clock_cost_estimation_iterations = 10000;
|
||||
|
||||
template <typename Clock>
|
||||
int warmup() {
|
||||
return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
|
||||
.iterations;
|
||||
}
|
||||
template <typename Clock>
|
||||
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
|
||||
auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
|
||||
.result;
|
||||
return {
|
||||
FloatDuration<Clock>(mean(r.begin(), r.end())),
|
||||
classify_outliers(r.begin(), r.end()),
|
||||
};
|
||||
}
|
||||
template <typename Clock>
|
||||
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
|
||||
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
|
||||
auto time_clock = [](int k) {
|
||||
return Detail::measure<Clock>([k] {
|
||||
for (int i = 0; i < k; ++i) {
|
||||
volatile auto ignored = Clock::now();
|
||||
(void)ignored;
|
||||
}
|
||||
}).elapsed;
|
||||
};
|
||||
time_clock(1);
|
||||
int iters = clock_cost_estimation_iterations;
|
||||
auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
|
||||
std::vector<double> times;
|
||||
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
|
||||
times.reserve(nsamples);
|
||||
std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
|
||||
return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
|
||||
});
|
||||
return {
|
||||
FloatDuration<Clock>(mean(times.begin(), times.end())),
|
||||
classify_outliers(times.begin(), times.end()),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Clock>
|
||||
Environment<FloatDuration<Clock>> measure_environment() {
|
||||
static Environment<FloatDuration<Clock>>* env = nullptr;
|
||||
if (env) {
|
||||
return *env;
|
||||
}
|
||||
|
||||
auto iters = Detail::warmup<Clock>();
|
||||
auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
|
||||
auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
|
||||
|
||||
env = new Environment<FloatDuration<Clock>>{ resolution, cost };
|
||||
return *env;
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_MEASURE_HPP_INCLUDED
|
||||
#define CATCH_MEASURE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock, typename Fun, typename... Args>
|
||||
TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
||||
auto start = Clock::now();
|
||||
auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
|
||||
auto end = Clock::now();
|
||||
auto delta = end - start;
|
||||
return { delta, std::forward<decltype(r)>(r), 1 };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_MEASURE_HPP_INCLUDED
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_REPEAT_HPP_INCLUDED
|
||||
#define CATCH_REPEAT_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Fun>
|
||||
struct repeater {
|
||||
void operator()(int k) const {
|
||||
for (int i = 0; i < k; ++i) {
|
||||
fun();
|
||||
}
|
||||
}
|
||||
Fun fun;
|
||||
};
|
||||
template <typename Fun>
|
||||
repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
|
||||
return { std::forward<Fun>(fun) };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_REPEAT_HPP_INCLUDED
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
|
||||
return Detail::measure<Clock>(fun, iters);
|
||||
}
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
|
||||
Detail::ChronometerModel<Clock> meter;
|
||||
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
|
||||
|
||||
return { meter.elapsed(), std::move(result), iters };
|
||||
}
|
||||
|
||||
template <typename Clock, typename Fun>
|
||||
using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
|
||||
|
||||
|
||||
[[noreturn]]
|
||||
void throw_optimized_away_error();
|
||||
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
|
||||
auto iters = seed;
|
||||
while (iters < (1 << 30)) {
|
||||
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
|
||||
|
||||
if (Timing.elapsed >= how_long) {
|
||||
return { Timing.elapsed, std::move(Timing.result), iters };
|
||||
}
|
||||
iters *= 2;
|
||||
}
|
||||
throw_optimized_away_error();
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
@@ -1,241 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
using Catch::Benchmark::Detail::sample;
|
||||
|
||||
template <typename URng, typename Estimator>
|
||||
sample resample(URng& rng, int resamples, std::vector<double>::iterator first, std::vector<double>::iterator last, Estimator& estimator) {
|
||||
auto n = last - first;
|
||||
std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
|
||||
|
||||
sample out;
|
||||
out.reserve(resamples);
|
||||
std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
|
||||
std::vector<double> resampled;
|
||||
resampled.reserve(n);
|
||||
std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
|
||||
return estimator(resampled.begin(), resampled.end());
|
||||
});
|
||||
std::sort(out.begin(), out.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
double erf_inv(double x) {
|
||||
// Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
|
||||
double w, p;
|
||||
|
||||
w = -log((1.0 - x) * (1.0 + x));
|
||||
|
||||
if (w < 6.250000) {
|
||||
w = w - 3.125000;
|
||||
p = -3.6444120640178196996e-21;
|
||||
p = -1.685059138182016589e-19 + p * w;
|
||||
p = 1.2858480715256400167e-18 + p * w;
|
||||
p = 1.115787767802518096e-17 + p * w;
|
||||
p = -1.333171662854620906e-16 + p * w;
|
||||
p = 2.0972767875968561637e-17 + p * w;
|
||||
p = 6.6376381343583238325e-15 + p * w;
|
||||
p = -4.0545662729752068639e-14 + p * w;
|
||||
p = -8.1519341976054721522e-14 + p * w;
|
||||
p = 2.6335093153082322977e-12 + p * w;
|
||||
p = -1.2975133253453532498e-11 + p * w;
|
||||
p = -5.4154120542946279317e-11 + p * w;
|
||||
p = 1.051212273321532285e-09 + p * w;
|
||||
p = -4.1126339803469836976e-09 + p * w;
|
||||
p = -2.9070369957882005086e-08 + p * w;
|
||||
p = 4.2347877827932403518e-07 + p * w;
|
||||
p = -1.3654692000834678645e-06 + p * w;
|
||||
p = -1.3882523362786468719e-05 + p * w;
|
||||
p = 0.0001867342080340571352 + p * w;
|
||||
p = -0.00074070253416626697512 + p * w;
|
||||
p = -0.0060336708714301490533 + p * w;
|
||||
p = 0.24015818242558961693 + p * w;
|
||||
p = 1.6536545626831027356 + p * w;
|
||||
} else if (w < 16.000000) {
|
||||
w = sqrt(w) - 3.250000;
|
||||
p = 2.2137376921775787049e-09;
|
||||
p = 9.0756561938885390979e-08 + p * w;
|
||||
p = -2.7517406297064545428e-07 + p * w;
|
||||
p = 1.8239629214389227755e-08 + p * w;
|
||||
p = 1.5027403968909827627e-06 + p * w;
|
||||
p = -4.013867526981545969e-06 + p * w;
|
||||
p = 2.9234449089955446044e-06 + p * w;
|
||||
p = 1.2475304481671778723e-05 + p * w;
|
||||
p = -4.7318229009055733981e-05 + p * w;
|
||||
p = 6.8284851459573175448e-05 + p * w;
|
||||
p = 2.4031110387097893999e-05 + p * w;
|
||||
p = -0.0003550375203628474796 + p * w;
|
||||
p = 0.00095328937973738049703 + p * w;
|
||||
p = -0.0016882755560235047313 + p * w;
|
||||
p = 0.0024914420961078508066 + p * w;
|
||||
p = -0.0037512085075692412107 + p * w;
|
||||
p = 0.005370914553590063617 + p * w;
|
||||
p = 1.0052589676941592334 + p * w;
|
||||
p = 3.0838856104922207635 + p * w;
|
||||
} else {
|
||||
w = sqrt(w) - 5.000000;
|
||||
p = -2.7109920616438573243e-11;
|
||||
p = -2.5556418169965252055e-10 + p * w;
|
||||
p = 1.5076572693500548083e-09 + p * w;
|
||||
p = -3.7894654401267369937e-09 + p * w;
|
||||
p = 7.6157012080783393804e-09 + p * w;
|
||||
p = -1.4960026627149240478e-08 + p * w;
|
||||
p = 2.9147953450901080826e-08 + p * w;
|
||||
p = -6.7711997758452339498e-08 + p * w;
|
||||
p = 2.2900482228026654717e-07 + p * w;
|
||||
p = -9.9298272942317002539e-07 + p * w;
|
||||
p = 4.5260625972231537039e-06 + p * w;
|
||||
p = -1.9681778105531670567e-05 + p * w;
|
||||
p = 7.5995277030017761139e-05 + p * w;
|
||||
p = -0.00021503011930044477347 + p * w;
|
||||
p = -0.00013871931833623122026 + p * w;
|
||||
p = 1.0103004648645343977 + p * w;
|
||||
p = 4.8499064014085844221 + p * w;
|
||||
}
|
||||
return p * x;
|
||||
}
|
||||
|
||||
double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||
auto m = Catch::Benchmark::Detail::mean(first, last);
|
||||
double variance = std::accumulate(first, last, 0., [m](double a, double b) {
|
||||
double diff = b - m;
|
||||
return a + diff * diff;
|
||||
}) / (last - first);
|
||||
return std::sqrt(variance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
|
||||
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||
auto count = last - first;
|
||||
double idx = (count - 1) * k / static_cast<double>(q);
|
||||
int j = static_cast<int>(idx);
|
||||
double g = idx - j;
|
||||
std::nth_element(first, first + j, last);
|
||||
auto xj = first[j];
|
||||
if (g == 0) return xj;
|
||||
|
||||
auto xj1 = *std::min_element(first + (j + 1), last);
|
||||
return xj + g * (xj1 - xj);
|
||||
}
|
||||
|
||||
|
||||
double erfc_inv(double x) {
|
||||
return erf_inv(1.0 - x);
|
||||
}
|
||||
|
||||
double normal_quantile(double p) {
|
||||
static const double ROOT_TWO = std::sqrt(2.0);
|
||||
|
||||
double result = 0.0;
|
||||
assert(p >= 0 && p <= 1);
|
||||
if (p < 0 || p > 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = -erfc_inv(2.0 * p);
|
||||
// result *= normal distribution standard deviation (1.0) * sqrt(2)
|
||||
result *= /*sd * */ ROOT_TWO;
|
||||
// result += normal disttribution mean (0)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
|
||||
double sb = stddev.point;
|
||||
double mn = mean.point / n;
|
||||
double mg_min = mn / 2.;
|
||||
double sg = std::min(mg_min / 4., sb / std::sqrt(n));
|
||||
double sg2 = sg * sg;
|
||||
double sb2 = sb * sb;
|
||||
|
||||
auto c_max = [n, mn, sb2, sg2](double x) -> double {
|
||||
double k = mn - x;
|
||||
double d = k * k;
|
||||
double nd = n * d;
|
||||
double k0 = -n * nd;
|
||||
double k1 = sb2 - n * sg2 + nd;
|
||||
double det = k1 * k1 - 4 * sg2 * k0;
|
||||
return static_cast<int>(-2. * k0 / (k1 + std::sqrt(det)));
|
||||
};
|
||||
|
||||
auto var_out = [n, sb2, sg2](double c) {
|
||||
double nc = n - c;
|
||||
return (nc / n) * (sb2 - nc * sg2);
|
||||
};
|
||||
|
||||
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
|
||||
}
|
||||
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static std::random_device entropy;
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
|
||||
|
||||
auto mean = &Detail::mean<std::vector<double>::iterator>;
|
||||
auto stddev = &standard_deviation;
|
||||
|
||||
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
|
||||
auto seed = entropy();
|
||||
return std::async(std::launch::async, [=] {
|
||||
std::mt19937 rng(seed);
|
||||
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||
return bootstrap(confidence_level, first, last, resampled, f);
|
||||
});
|
||||
};
|
||||
|
||||
auto mean_future = Estimate(mean);
|
||||
auto stddev_future = Estimate(stddev);
|
||||
|
||||
auto mean_estimate = mean_future.get();
|
||||
auto stddev_estimate = stddev_future.get();
|
||||
#else
|
||||
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
|
||||
auto seed = entropy();
|
||||
std::mt19937 rng(seed);
|
||||
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||
return bootstrap(confidence_level, first, last, resampled, f);
|
||||
};
|
||||
|
||||
auto mean_estimate = Estimate(mean);
|
||||
auto stddev_estimate = Estimate(stddev);
|
||||
#endif // CATCH_USE_ASYNC
|
||||
|
||||
double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
|
||||
|
||||
return { mean_estimate, stddev_estimate, outlier_variance };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
@@ -1,138 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_STATS_HPP_INCLUDED
|
||||
#define CATCH_STATS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
using sample = std::vector<double>;
|
||||
|
||||
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
|
||||
|
||||
template <typename Iterator>
|
||||
OutlierClassification classify_outliers(Iterator first, Iterator last) {
|
||||
std::vector<double> copy(first, last);
|
||||
|
||||
auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
|
||||
auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
|
||||
auto iqr = q3 - q1;
|
||||
auto los = q1 - (iqr * 3.);
|
||||
auto lom = q1 - (iqr * 1.5);
|
||||
auto him = q3 + (iqr * 1.5);
|
||||
auto his = q3 + (iqr * 3.);
|
||||
|
||||
OutlierClassification o;
|
||||
for (; first != last; ++first) {
|
||||
auto&& t = *first;
|
||||
if (t < los) ++o.low_severe;
|
||||
else if (t < lom) ++o.low_mild;
|
||||
else if (t > his) ++o.high_severe;
|
||||
else if (t > him) ++o.high_mild;
|
||||
++o.samples_seen;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
double mean(Iterator first, Iterator last) {
|
||||
auto count = last - first;
|
||||
double sum = std::accumulate(first, last, 0.);
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
template <typename Estimator, typename Iterator>
|
||||
sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
|
||||
auto n = last - first;
|
||||
auto second = first;
|
||||
++second;
|
||||
sample results;
|
||||
results.reserve(n);
|
||||
|
||||
for (auto it = first; it != last; ++it) {
|
||||
std::iter_swap(it, first);
|
||||
results.push_back(estimator(second, last));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
inline double normal_cdf(double x) {
|
||||
return std::erfc(-x / std::sqrt(2.0)) / 2.0;
|
||||
}
|
||||
|
||||
double erfc_inv(double x);
|
||||
|
||||
double normal_quantile(double p);
|
||||
|
||||
template <typename Iterator, typename Estimator>
|
||||
Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
|
||||
auto n_samples = last - first;
|
||||
|
||||
double point = estimator(first, last);
|
||||
// Degenerate case with a single sample
|
||||
if (n_samples == 1) return { point, point, point, confidence_level };
|
||||
|
||||
sample jack = jackknife(estimator, first, last);
|
||||
double jack_mean = mean(jack.begin(), jack.end());
|
||||
double sum_squares, sum_cubes;
|
||||
std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
|
||||
auto d = jack_mean - x;
|
||||
auto d2 = d * d;
|
||||
auto d3 = d2 * d;
|
||||
return { sqcb.first + d2, sqcb.second + d3 };
|
||||
});
|
||||
|
||||
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
|
||||
int n = static_cast<int>(resample.size());
|
||||
double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast<double>(n);
|
||||
// degenerate case with uniform samples
|
||||
if (prob_n == 0) return { point, point, point, confidence_level };
|
||||
|
||||
double bias = normal_quantile(prob_n);
|
||||
double z1 = normal_quantile((1. - confidence_level) / 2.);
|
||||
|
||||
auto cumn = [n](double x) -> int {
|
||||
return std::lround(normal_cdf(x) * n); };
|
||||
auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
|
||||
double b1 = bias + z1;
|
||||
double b2 = bias - z1;
|
||||
double a1 = a(b1);
|
||||
double a2 = a(b2);
|
||||
auto lo = std::max(cumn(a1), 0);
|
||||
auto hi = std::min(cumn(a2), n - 1);
|
||||
|
||||
return { point, resample[lo], resample[hi], confidence_level };
|
||||
}
|
||||
|
||||
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
|
||||
|
||||
struct bootstrap_analysis {
|
||||
Estimate<double> mean;
|
||||
Estimate<double> standard_deviation;
|
||||
double outlier_variance;
|
||||
};
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_STATS_HPP_INCLUDED
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_TIMING_HPP_INCLUDED
|
||||
#define CATCH_TIMING_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Duration, typename Result>
|
||||
struct Timing {
|
||||
Duration elapsed;
|
||||
Result result;
|
||||
int iterations;
|
||||
};
|
||||
template <typename Clock, typename Func, typename... Args>
|
||||
using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_TIMING_HPP_INCLUDED
|
||||
@@ -1,95 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/** \file
|
||||
* This is a special TU that combines what would otherwise be a very
|
||||
* small benchmarking-related TUs into one bigger TU.
|
||||
*
|
||||
* The reason for this is compilation performance improvements by
|
||||
* avoiding reparsing headers for many small TUs, instead having this
|
||||
* one TU include bit more, but having it all parsed only once.
|
||||
*
|
||||
* To avoid heavy-tail problem with compilation times, each "subpart"
|
||||
* of Catch2 has its own combined TU like this.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////
|
||||
// vvv formerly catch_chronometer.cpp vvv //
|
||||
////////////////////////////////////////////
|
||||
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
ChronometerConcept::~ChronometerConcept() = default;
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// vvv formerly catch_benchmark_function.cpp vvv //
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
BenchmarkFunction::callable::~callable() = default;
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// vvv formerly catch_complete_invoke.cpp vvv //
|
||||
////////////////////////////////////////////////
|
||||
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// vvv formerly catch_run_for_at_least.cpp vvv //
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <exception>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
struct optimized_away_error : std::exception {
|
||||
const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
const char* optimized_away_error::what() const noexcept {
|
||||
return "could not measure benchmark, maybe it was optimized away";
|
||||
}
|
||||
|
||||
void throw_optimized_away_error() {
|
||||
Catch::throw_exception(optimized_away_error{});
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
@@ -1,111 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/** \file
|
||||
* This is a convenience header for Catch2. It includes **all** of Catch2 headers.
|
||||
*
|
||||
* Generally the Catch2 users should use specific includes they need,
|
||||
* but this header can be used instead for ease-of-experimentation, or
|
||||
* just plain convenience, at the cost of (significantly) increased
|
||||
* compilation times.
|
||||
*
|
||||
* When a new header is added to either the top level folder, or to the
|
||||
* corresponding internal subfolder, it should be added here. Headers
|
||||
* added to the various subparts (e.g. matchers, generators, etc...),
|
||||
* should go their respective catch-all headers.
|
||||
*/
|
||||
|
||||
#ifndef CATCH_ALL_HPP_INCLUDED
|
||||
#define CATCH_ALL_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_benchmark_all.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_reporter_registrars.hpp>
|
||||
#include <catch2/catch_section_info.hpp>
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/catch_tag_alias.hpp>
|
||||
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/catch_version.hpp>
|
||||
#include <catch2/catch_version_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_all.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_all.hpp>
|
||||
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||
#include <catch2/internal/catch_case_sensitive.hpp>
|
||||
#include <catch2/internal/catch_clara.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_config_android_logwrite.hpp>
|
||||
#include <catch2/internal/catch_config_counter.hpp>
|
||||
#include <catch2/internal/catch_config_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_console_width.hpp>
|
||||
#include <catch2/internal/catch_container_nonmembers.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_debug_console.hpp>
|
||||
#include <catch2/internal/catch_debugger.hpp>
|
||||
#include <catch2/internal/catch_decomposer.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/internal/catch_errno_guard.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_option.hpp>
|
||||
#include <catch2/internal/catch_output_redirect.hpp>
|
||||
#include <catch2/internal/catch_platform.hpp>
|
||||
#include <catch2/internal/catch_polyfills.hpp>
|
||||
#include <catch2/internal/catch_preprocessor.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_section.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_template_test_registry.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_test_macro_impl.hpp>
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_to_string.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_all.hpp>
|
||||
#include <catch2/reporters/catch_reporters_all.hpp>
|
||||
|
||||
#endif // CATCH_ALL_HPP_INCLUDED
|
||||
@@ -1,84 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Approx::Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_margin( 0.0 ),
|
||||
m_scale( 0.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
|
||||
Approx Approx::custom() {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
Approx Approx::operator-() const {
|
||||
auto temp(*this);
|
||||
temp.m_value = -temp.m_value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
std::string Approx::toString() const {
|
||||
ReusableStringStream rss;
|
||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
bool Approx::equalityComparisonImpl(const double other) const {
|
||||
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
|
||||
// Thanks to Richard Harris for his help refining the scaled margin value
|
||||
return marginComparison(m_value, other, m_margin)
|
||||
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
|
||||
}
|
||||
|
||||
void Approx::setMargin(double newMargin) {
|
||||
CATCH_ENFORCE(newMargin >= 0,
|
||||
"Invalid Approx::margin: " << newMargin << '.'
|
||||
<< " Approx::Margin has to be non-negative.");
|
||||
m_margin = newMargin;
|
||||
}
|
||||
|
||||
void Approx::setEpsilon(double newEpsilon) {
|
||||
CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
|
||||
"Invalid Approx::epsilon: " << newEpsilon << '.'
|
||||
<< " Approx::epsilon has to be in [0, 1]");
|
||||
m_epsilon = newEpsilon;
|
||||
}
|
||||
|
||||
namespace literals {
|
||||
Approx operator "" _a(long double val) {
|
||||
return Approx(val);
|
||||
}
|
||||
Approx operator "" _a(unsigned long long val) {
|
||||
return Approx(val);
|
||||
}
|
||||
} // end namespace literals
|
||||
|
||||
std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,128 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_APPROX_HPP_INCLUDED
|
||||
#define CATCH_APPROX_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Approx {
|
||||
private:
|
||||
bool equalityComparisonImpl(double other) const;
|
||||
// Sets and validates the new margin (margin >= 0)
|
||||
void setMargin(double margin);
|
||||
// Sets and validates the new epsilon (0 < epsilon < 1)
|
||||
void setEpsilon(double epsilon);
|
||||
|
||||
public:
|
||||
explicit Approx ( double value );
|
||||
|
||||
static Approx custom();
|
||||
|
||||
Approx operator-() const;
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx operator()( T const& value ) {
|
||||
Approx approx( static_cast<double>(value) );
|
||||
approx.m_epsilon = m_epsilon;
|
||||
approx.m_margin = m_margin;
|
||||
approx.m_scale = m_scale;
|
||||
return approx;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
explicit Approx( T const& value ): Approx(static_cast<double>(value))
|
||||
{}
|
||||
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||
auto lhs_v = static_cast<double>(lhs);
|
||||
return rhs.equalityComparisonImpl(lhs_v);
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
||||
return operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator != ( T const& lhs, Approx const& rhs ) {
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator != ( Approx const& lhs, T const& rhs ) {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator <= ( Approx const& lhs, T const& rhs ) {
|
||||
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator >= ( Approx const& lhs, T const& rhs ) {
|
||||
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& epsilon( T const& newEpsilon ) {
|
||||
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||
setEpsilon(epsilonAsDouble);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& margin( T const& newMargin ) {
|
||||
double marginAsDouble = static_cast<double>(newMargin);
|
||||
setMargin(marginAsDouble);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& scale( T const& newScale ) {
|
||||
m_scale = static_cast<double>(newScale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
double m_epsilon;
|
||||
double m_margin;
|
||||
double m_scale;
|
||||
double m_value;
|
||||
};
|
||||
|
||||
namespace literals {
|
||||
Approx operator "" _a(long double val);
|
||||
Approx operator "" _a(unsigned long long val);
|
||||
} // end namespace literals
|
||||
|
||||
template<>
|
||||
struct StringMaker<Catch::Approx> {
|
||||
static std::string convert(Catch::Approx const& value);
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_APPROX_HPP_INCLUDED
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
#define CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionInfo {
|
||||
// AssertionInfo() = delete;
|
||||
|
||||
StringRef macroName;
|
||||
SourceLineInfo lineInfo;
|
||||
StringRef capturedExpression;
|
||||
ResultDisposition::Flags resultDisposition;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
@@ -1,105 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
|
||||
lazyExpression(_lazyExpression),
|
||||
resultType(_resultType) {}
|
||||
|
||||
std::string AssertionResultData::reconstructExpression() const {
|
||||
|
||||
if( reconstructedExpression.empty() ) {
|
||||
if( lazyExpression ) {
|
||||
ReusableStringStream rss;
|
||||
rss << lazyExpression;
|
||||
reconstructedExpression = rss.str();
|
||||
}
|
||||
}
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
||||
: m_info( info ),
|
||||
m_resultData( data )
|
||||
{}
|
||||
|
||||
// Result was a success
|
||||
bool AssertionResult::succeeded() const {
|
||||
return Catch::isOk( m_resultData.resultType );
|
||||
}
|
||||
|
||||
// Result was a success, or failure is suppressed
|
||||
bool AssertionResult::isOk() const {
|
||||
return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
|
||||
}
|
||||
|
||||
ResultWas::OfType AssertionResult::getResultType() const {
|
||||
return m_resultData.resultType;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpression() const {
|
||||
return !m_info.capturedExpression.empty();
|
||||
}
|
||||
|
||||
bool AssertionResult::hasMessage() const {
|
||||
return !m_resultData.message.empty();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
// Possibly overallocating by 3 characters should be basically free
|
||||
std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
|
||||
if (isFalseTest(m_info.resultDisposition)) {
|
||||
expr += "!(";
|
||||
}
|
||||
expr += m_info.capturedExpression;
|
||||
if (isFalseTest(m_info.resultDisposition)) {
|
||||
expr += ')';
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpressionInMacro() const {
|
||||
std::string expr;
|
||||
if( m_info.macroName.empty() )
|
||||
expr = static_cast<std::string>(m_info.capturedExpression);
|
||||
else {
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpandedExpression() const {
|
||||
return hasExpression() && getExpandedExpression() != getExpression();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpandedExpression() const {
|
||||
std::string expr = m_resultData.reconstructExpression();
|
||||
return expr.empty()
|
||||
? getExpression()
|
||||
: expr;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getMessage() const {
|
||||
return m_resultData.message;
|
||||
}
|
||||
SourceLineInfo AssertionResult::getSourceInfo() const {
|
||||
return m_info.lineInfo;
|
||||
}
|
||||
|
||||
StringRef AssertionResult::getTestMacroName() const {
|
||||
return m_info.macroName;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,60 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionResultData
|
||||
{
|
||||
AssertionResultData() = delete;
|
||||
|
||||
AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
|
||||
|
||||
std::string message;
|
||||
mutable std::string reconstructedExpression;
|
||||
LazyExpression lazyExpression;
|
||||
ResultWas::OfType resultType;
|
||||
|
||||
std::string reconstructExpression() const;
|
||||
};
|
||||
|
||||
class AssertionResult {
|
||||
public:
|
||||
AssertionResult() = delete;
|
||||
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
|
||||
|
||||
bool isOk() const;
|
||||
bool succeeded() const;
|
||||
ResultWas::OfType getResultType() const;
|
||||
bool hasExpression() const;
|
||||
bool hasMessage() const;
|
||||
std::string getExpression() const;
|
||||
std::string getExpressionInMacro() const;
|
||||
bool hasExpandedExpression() const;
|
||||
std::string getExpandedExpression() const;
|
||||
std::string getMessage() const;
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
StringRef getTestMacroName() const;
|
||||
|
||||
//protected:
|
||||
AssertionInfo m_info;
|
||||
AssertionResultData m_resultData;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
@@ -1,93 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Config::Config( ConfigData const& data )
|
||||
: m_data( data ),
|
||||
m_stream( openStream() )
|
||||
{
|
||||
// We need to trim filter specs to avoid trouble with superfluous
|
||||
// whitespace (esp. important for bdd macros, as those are manually
|
||||
// aligned with whitespace).
|
||||
|
||||
for (auto& elem : m_data.testsOrTags) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
for (auto& elem : m_data.sectionsToRun) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
|
||||
TestSpecParser parser(ITagAliasRegistry::get());
|
||||
if (!m_data.testsOrTags.empty()) {
|
||||
m_hasTestFilters = true;
|
||||
for (auto const& testOrTags : m_data.testsOrTags) {
|
||||
parser.parse(testOrTags);
|
||||
}
|
||||
}
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
|
||||
Config::~Config() = default;
|
||||
|
||||
|
||||
std::string const& Config::getFilename() const {
|
||||
return m_data.outputFilename ;
|
||||
}
|
||||
|
||||
bool Config::listTests() const { return m_data.listTests; }
|
||||
bool Config::listTags() const { return m_data.listTags; }
|
||||
bool Config::listReporters() const { return m_data.listReporters; }
|
||||
|
||||
std::string Config::getProcessName() const { return m_data.processName; }
|
||||
std::string const& Config::getReporterName() const { return m_data.reporterName; }
|
||||
|
||||
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
|
||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
// IConfig interface
|
||||
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||
std::ostream& Config::stream() const { return m_stream->stream(); }
|
||||
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
|
||||
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
|
||||
ShowDurations Config::showDurations() const { return m_data.showDurations; }
|
||||
double Config::minDuration() const { return m_data.minDuration; }
|
||||
TestRunOrder Config::runOrder() const { return m_data.runOrder; }
|
||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||
UseColour Config::useColour() const { return m_data.useColour; }
|
||||
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
int Config::abortAfter() const { return m_data.abortAfter; }
|
||||
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||
|
||||
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
|
||||
int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
|
||||
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
|
||||
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
|
||||
std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
|
||||
|
||||
IStream const* Config::openStream() {
|
||||
return Catch::makeStream(m_data.outputFilename);
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,124 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_CONFIG_HPP_INCLUDED
|
||||
#define CATCH_CONFIG_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct IStream;
|
||||
|
||||
struct ConfigData {
|
||||
bool listTests = false;
|
||||
bool listTags = false;
|
||||
bool listReporters = false;
|
||||
|
||||
bool showSuccessfulTests = false;
|
||||
bool shouldDebugBreak = false;
|
||||
bool noThrow = false;
|
||||
bool showHelp = false;
|
||||
bool showInvisibles = false;
|
||||
bool filenamesAsTags = false;
|
||||
bool libIdentify = false;
|
||||
|
||||
int abortAfter = -1;
|
||||
unsigned int rngSeed = 0;
|
||||
|
||||
bool benchmarkNoAnalysis = false;
|
||||
unsigned int benchmarkSamples = 100;
|
||||
double benchmarkConfidenceInterval = 0.95;
|
||||
unsigned int benchmarkResamples = 100000;
|
||||
std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
|
||||
|
||||
Verbosity verbosity = Verbosity::Normal;
|
||||
WarnAbout::What warnings = WarnAbout::Nothing;
|
||||
ShowDurations showDurations = ShowDurations::DefaultForReporter;
|
||||
double minDuration = -1;
|
||||
TestRunOrder runOrder = TestRunOrder::Declared;
|
||||
UseColour useColour = UseColour::Auto;
|
||||
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
||||
|
||||
std::string outputFilename;
|
||||
std::string name;
|
||||
std::string processName;
|
||||
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
||||
#endif
|
||||
std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
|
||||
#undef CATCH_CONFIG_DEFAULT_REPORTER
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
};
|
||||
|
||||
|
||||
class Config : public IConfig {
|
||||
public:
|
||||
|
||||
Config() = default;
|
||||
Config( ConfigData const& data );
|
||||
~Config() override; // = default in the cpp file
|
||||
|
||||
std::string const& getFilename() const;
|
||||
|
||||
bool listTests() const;
|
||||
bool listTags() const;
|
||||
bool listReporters() const;
|
||||
|
||||
std::string getProcessName() const;
|
||||
std::string const& getReporterName() const;
|
||||
|
||||
std::vector<std::string> const& getTestsOrTags() const override;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
TestSpec const& testSpec() const override;
|
||||
bool hasTestFilters() const override;
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
std::ostream& stream() const override;
|
||||
std::string name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
bool warnAboutNoTests() const override;
|
||||
ShowDurations showDurations() const override;
|
||||
double minDuration() const override;
|
||||
TestRunOrder runOrder() const override;
|
||||
unsigned int rngSeed() const override;
|
||||
UseColour useColour() const override;
|
||||
bool shouldDebugBreak() const override;
|
||||
int abortAfter() const override;
|
||||
bool showInvisibles() const override;
|
||||
Verbosity verbosity() const override;
|
||||
bool benchmarkNoAnalysis() const override;
|
||||
int benchmarkSamples() const override;
|
||||
double benchmarkConfidenceInterval() const override;
|
||||
unsigned int benchmarkResamples() const override;
|
||||
std::chrono::milliseconds benchmarkWarmupTime() const override;
|
||||
|
||||
private:
|
||||
|
||||
IStream const* openStream();
|
||||
ConfigData m_data;
|
||||
|
||||
Detail::unique_ptr<IStream const> m_stream;
|
||||
TestSpec m_testSpec;
|
||||
bool m_hasTestFilters = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_CONFIG_HPP_INCLUDED
|
||||
@@ -1,118 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
ResultWas::OfType type )
|
||||
:m_info(macroName, lineInfo, type) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
|
||||
m_info( builder.m_info ) {
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
||||
m_info( std::move( old.m_info ) ) {
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !uncaught_exceptions() && !m_moved ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
|
||||
auto trimmed = [&] (size_t start, size_t end) {
|
||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||
++start;
|
||||
}
|
||||
while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
|
||||
--end;
|
||||
}
|
||||
return names.substr(start, end - start + 1);
|
||||
};
|
||||
auto skipq = [&] (size_t start, char quote) {
|
||||
for (auto i = start + 1; i < names.size() ; ++i) {
|
||||
if (names[i] == quote)
|
||||
return i;
|
||||
if (names[i] == '\\')
|
||||
++i;
|
||||
}
|
||||
CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
|
||||
};
|
||||
|
||||
size_t start = 0;
|
||||
std::stack<char> openings;
|
||||
for (size_t pos = 0; pos < names.size(); ++pos) {
|
||||
char c = names[pos];
|
||||
switch (c) {
|
||||
case '[':
|
||||
case '{':
|
||||
case '(':
|
||||
// It is basically impossible to disambiguate between
|
||||
// comparison and start of template args in this context
|
||||
// case '<':
|
||||
openings.push(c);
|
||||
break;
|
||||
case ']':
|
||||
case '}':
|
||||
case ')':
|
||||
// case '>':
|
||||
openings.pop();
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
pos = skipq(pos, c);
|
||||
break;
|
||||
case ',':
|
||||
if (start != pos && openings.empty()) {
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
|
||||
m_messages.back().message += " := ";
|
||||
start = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(openings.empty() && "Mismatched openings");
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
|
||||
m_messages.back().message += " := ";
|
||||
}
|
||||
Capturer::~Capturer() {
|
||||
if ( !uncaught_exceptions() ){
|
||||
assert( m_captured == m_messages.size() );
|
||||
for( size_t i = 0; i < m_captured; ++i )
|
||||
m_resultCapture.popScopedMessage( m_messages[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void Capturer::captureValue( size_t index, std::string const& value ) {
|
||||
assert( index < m_messages.size() );
|
||||
m_messages[index].message += value;
|
||||
m_resultCapture.pushScopedMessage( m_messages[index] );
|
||||
m_captured++;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,144 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_MESSAGE_HPP_INCLUDED
|
||||
#define CATCH_MESSAGE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SourceLineInfo;
|
||||
|
||||
struct MessageStream {
|
||||
|
||||
template<typename T>
|
||||
MessageStream& operator << ( T const& value ) {
|
||||
m_stream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReusableStringStream m_stream;
|
||||
};
|
||||
|
||||
struct MessageBuilder : MessageStream {
|
||||
MessageBuilder( StringRef const& macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
ResultWas::OfType type );
|
||||
|
||||
template<typename T>
|
||||
MessageBuilder& operator << ( T const& value ) {
|
||||
m_stream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MessageInfo m_info;
|
||||
};
|
||||
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old ) noexcept;
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
bool m_moved = false;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
std::vector<MessageInfo> m_messages;
|
||||
IResultCapture& m_resultCapture = getResultCapture();
|
||||
size_t m_captured = 0;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
|
||||
Capturer(Capturer const&) = delete;
|
||||
Capturer& operator=(Capturer const&) = delete;
|
||||
|
||||
~Capturer();
|
||||
|
||||
void captureValue( size_t index, std::string const& value );
|
||||
|
||||
template<typename T>
|
||||
void captureValues( size_t index, T const& value ) {
|
||||
captureValue( index, Catch::Detail::stringify( value ) );
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void captureValues( size_t index, T const& value, Ts const&... values ) {
|
||||
captureValue( index, Catch::Detail::stringify(value) );
|
||||
captureValues( index+1, values... );
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||
Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
|
||||
varName.captureValues( 0, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
|
||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
|
||||
|
||||
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_INFO( msg ) (void)(0)
|
||||
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define CATCH_WARN( msg ) (void)(0)
|
||||
#define CATCH_CAPTURE( ... ) (void)(0)
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) (void)(0)
|
||||
#define UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define WARN( msg ) (void)(0)
|
||||
#define CAPTURE( ... ) (void)(0)
|
||||
|
||||
#endif // end of user facing macro declarations
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CATCH_MESSAGE_HPP_INCLUDED
|
||||
@@ -1,103 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
|
||||
class RegistryHub : public IRegistryHub,
|
||||
public IMutableRegistryHub,
|
||||
private Detail::NonCopyable {
|
||||
|
||||
public: // IRegistryHub
|
||||
RegistryHub() = default;
|
||||
IReporterRegistry const& getReporterRegistry() const override {
|
||||
return m_reporterRegistry;
|
||||
}
|
||||
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
||||
return m_testCaseRegistry;
|
||||
}
|
||||
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
|
||||
return m_exceptionTranslatorRegistry;
|
||||
}
|
||||
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
||||
return m_tagAliasRegistry;
|
||||
}
|
||||
StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
|
||||
return m_exceptionRegistry;
|
||||
}
|
||||
|
||||
public: // IMutableRegistryHub
|
||||
void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
|
||||
m_reporterRegistry.registerReporter( name, std::move(factory) );
|
||||
}
|
||||
void registerListener( IReporterFactoryPtr factory ) override {
|
||||
m_reporterRegistry.registerListener( std::move(factory) );
|
||||
}
|
||||
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
|
||||
m_testCaseRegistry.registerTest( std::move(testInfo), std::move(invoker) );
|
||||
}
|
||||
void registerTranslator( const IExceptionTranslator* translator ) override {
|
||||
m_exceptionTranslatorRegistry.registerTranslator( translator );
|
||||
}
|
||||
void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
|
||||
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||
}
|
||||
void registerStartupException() noexcept override {
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
m_exceptionRegistry.add(std::current_exception());
|
||||
#else
|
||||
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
#endif
|
||||
}
|
||||
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
||||
return m_enumValuesRegistry;
|
||||
}
|
||||
|
||||
private:
|
||||
TestRegistry m_testCaseRegistry;
|
||||
ReporterRegistry m_reporterRegistry;
|
||||
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
||||
TagAliasRegistry m_tagAliasRegistry;
|
||||
StartupExceptionRegistry m_exceptionRegistry;
|
||||
Detail::EnumValuesRegistry m_enumValuesRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
|
||||
|
||||
IRegistryHub const& getRegistryHub() {
|
||||
return RegistryHubSingleton::get();
|
||||
}
|
||||
IMutableRegistryHub& getMutableRegistryHub() {
|
||||
return RegistryHubSingleton::getMutable();
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
cleanUpContext();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,83 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
|
||||
#define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct IStreamingReporter;
|
||||
using IStreamingReporterPtr = Detail::unique_ptr<IStreamingReporter>;
|
||||
|
||||
template <typename T>
|
||||
class ReporterFactory : public IReporterFactory {
|
||||
|
||||
IStreamingReporterPtr create( ReporterConfig const& config ) const override {
|
||||
return Detail::make_unique<T>( config );
|
||||
}
|
||||
|
||||
std::string getDescription() const override {
|
||||
return T::getDescription();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ReporterRegistrar {
|
||||
public:
|
||||
explicit ReporterRegistrar( std::string const& name ) {
|
||||
getMutableRegistryHub().registerReporter( name, Detail::make_unique<ReporterFactory<T>>() );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ListenerRegistrar {
|
||||
|
||||
class ListenerFactory : public IReporterFactory {
|
||||
|
||||
IStreamingReporterPtr create( ReporterConfig const& config ) const override {
|
||||
return Detail::make_unique<T>(config);
|
||||
}
|
||||
std::string getDescription() const override {
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
ListenerRegistrar() {
|
||||
getMutableRegistryHub().registerListener( Detail::make_unique<ListenerFactory>() );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#define CATCH_REGISTER_LISTENER( listenerType ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
#else // CATCH_CONFIG_DISABLE
|
||||
|
||||
#define CATCH_REGISTER_REPORTER(name, reporterType)
|
||||
#define CATCH_REGISTER_LISTENER(listenerType)
|
||||
|
||||
#endif // CATCH_CONFIG_DISABLE
|
||||
|
||||
#endif // CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
#define CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SectionInfo {
|
||||
// The last argument is ignored, so that people can write
|
||||
// SECTION("ShortName", "Proper description that is long") and
|
||||
// still use the `-c` flag comfortably.
|
||||
SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
|
||||
const char* const = nullptr ):
|
||||
name(std::move(_name)),
|
||||
lineInfo(_lineInfo)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
struct SectionEndInfo {
|
||||
SectionInfo sectionInfo;
|
||||
Counts prevAssertions;
|
||||
double durationInSeconds;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
@@ -1,305 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_stream.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/catch_version.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/reporters/catch_reporter_listening.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
const int MaxExitCode = 255;
|
||||
|
||||
IStreamingReporterPtr createReporter(std::string const& reporterName, IConfig const* config) {
|
||||
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
|
||||
CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
|
||||
|
||||
return reporter;
|
||||
}
|
||||
|
||||
IStreamingReporterPtr makeReporter(Config const* config) {
|
||||
if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
|
||||
return createReporter(config->getReporterName(), config);
|
||||
}
|
||||
|
||||
// On older platforms, returning unique_ptr<ListeningReporter>
|
||||
// when the return type is unique_ptr<IStreamingReporter>
|
||||
// doesn't compile without a std::move call. However, this causes
|
||||
// a warning on newer platforms. Thus, we have to work around
|
||||
// it a bit and downcast the pointer manually.
|
||||
auto ret = Detail::unique_ptr<IStreamingReporter>(new ListeningReporter(config));
|
||||
auto& multi = static_cast<ListeningReporter&>(*ret);
|
||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||
for (auto const& listener : listeners) {
|
||||
multi.addListener(listener->create(Catch::ReporterConfig(config)));
|
||||
}
|
||||
multi.addReporter(createReporter(config->getReporterName(), config));
|
||||
return ret;
|
||||
}
|
||||
|
||||
class TestGroup {
|
||||
public:
|
||||
explicit TestGroup(IStreamingReporterPtr&& reporter, Config const* config):
|
||||
m_reporter(reporter.get()),
|
||||
m_config{config},
|
||||
m_context{config, std::move(reporter)} {
|
||||
|
||||
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
||||
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
|
||||
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
||||
|
||||
if (m_matches.empty() && invalidArgs.empty()) {
|
||||
for (auto const& test : allTestCases)
|
||||
if (!test.getTestCaseInfo().isHidden())
|
||||
m_tests.emplace(&test);
|
||||
} else {
|
||||
for (auto const& match : m_matches)
|
||||
m_tests.insert(match.tests.begin(), match.tests.end());
|
||||
}
|
||||
}
|
||||
|
||||
Totals execute() {
|
||||
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
||||
Totals totals;
|
||||
m_context.testGroupStarting(m_config->name(), 1, 1);
|
||||
for (auto const& testCase : m_tests) {
|
||||
if (!m_context.aborting())
|
||||
totals += m_context.runTest(*testCase);
|
||||
else
|
||||
m_reporter->skipTest(testCase->getTestCaseInfo());
|
||||
}
|
||||
|
||||
for (auto const& match : m_matches) {
|
||||
if (match.tests.empty()) {
|
||||
m_reporter->noMatchingTestCases(match.name);
|
||||
totals.error = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!invalidArgs.empty()) {
|
||||
for (auto const& invalidArg: invalidArgs)
|
||||
m_reporter->reportInvalidArguments(invalidArg);
|
||||
}
|
||||
|
||||
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
|
||||
return totals;
|
||||
}
|
||||
|
||||
private:
|
||||
using Tests = std::set<TestCaseHandle const*>;
|
||||
|
||||
IStreamingReporter* m_reporter;
|
||||
Config const* m_config;
|
||||
RunContext m_context;
|
||||
Tests m_tests;
|
||||
TestSpec::Matches m_matches;
|
||||
};
|
||||
|
||||
void applyFilenamesAsTags() {
|
||||
for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
|
||||
testInfo->addFilenameTag();
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Session::Session() {
|
||||
static bool alreadyInstantiated = false;
|
||||
if( alreadyInstantiated ) {
|
||||
CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
|
||||
CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
|
||||
}
|
||||
|
||||
// There cannot be exceptions at startup in no-exception mode.
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||
if ( !exceptions.empty() ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
|
||||
m_startupExceptions = true;
|
||||
Colour colourGuard( Colour::Red );
|
||||
Catch::cerr() << "Errors occurred during startup!" << '\n';
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
std::rethrow_exception(ex_ptr);
|
||||
} catch ( std::exception const& ex ) {
|
||||
Catch::cerr() << TextFlow::Column( ex.what() ).indent(2) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
alreadyInstantiated = true;
|
||||
m_cli = makeCommandLineParser( m_configData );
|
||||
}
|
||||
Session::~Session() {
|
||||
Catch::cleanUp();
|
||||
}
|
||||
|
||||
void Session::showHelp() const {
|
||||
Catch::cout()
|
||||
<< "\nCatch v" << libraryVersion() << "\n"
|
||||
<< m_cli << std::endl
|
||||
<< "For more detailed usage please see the project docs\n" << std::endl;
|
||||
}
|
||||
void Session::libIdentify() {
|
||||
Catch::cout()
|
||||
<< std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
|
||||
<< std::left << std::setw(16) << "category: " << "testframework\n"
|
||||
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
|
||||
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
|
||||
}
|
||||
|
||||
int Session::applyCommandLine( int argc, char const * const * argv ) {
|
||||
if( m_startupExceptions )
|
||||
return 1;
|
||||
|
||||
auto result = m_cli.parse( Clara::Args( argc, argv ) );
|
||||
if( !result ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "\nError(s) in input:\n"
|
||||
<< TextFlow::Column( result.errorMessage() ).indent( 2 )
|
||||
<< "\n\n";
|
||||
Catch::cerr() << "Run with -? for usage\n" << std::endl;
|
||||
return MaxExitCode;
|
||||
}
|
||||
|
||||
if( m_configData.showHelp )
|
||||
showHelp();
|
||||
if( m_configData.libIdentify )
|
||||
libIdentify();
|
||||
m_config.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
|
||||
|
||||
char **utf8Argv = new char *[ argc ];
|
||||
|
||||
for ( int i = 0; i < argc; ++i ) {
|
||||
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
|
||||
|
||||
utf8Argv[ i ] = new char[ bufSize ];
|
||||
|
||||
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
|
||||
}
|
||||
|
||||
int returnCode = applyCommandLine( argc, utf8Argv );
|
||||
|
||||
for ( int i = 0; i < argc; ++i )
|
||||
delete [] utf8Argv[ i ];
|
||||
|
||||
delete [] utf8Argv;
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Session::useConfigData( ConfigData const& configData ) {
|
||||
m_configData = configData;
|
||||
m_config.reset();
|
||||
}
|
||||
|
||||
int Session::run() {
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
int exitCode = runInternal();
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
Clara::Parser const& Session::cli() const {
|
||||
return m_cli;
|
||||
}
|
||||
void Session::cli( Clara::Parser const& newParser ) {
|
||||
m_cli = newParser;
|
||||
}
|
||||
ConfigData& Session::configData() {
|
||||
return m_configData;
|
||||
}
|
||||
Config& Session::config() {
|
||||
if( !m_config )
|
||||
m_config = Detail::make_unique<Config>( m_configData );
|
||||
return *m_config;
|
||||
}
|
||||
|
||||
int Session::runInternal() {
|
||||
if( m_startupExceptions )
|
||||
return 1;
|
||||
|
||||
if (m_configData.showHelp || m_configData.libIdentify) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CATCH_TRY {
|
||||
config(); // Force config to be constructed
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
if (m_configData.filenamesAsTags) {
|
||||
applyFilenamesAsTags();
|
||||
}
|
||||
|
||||
// Set up global config instance before we start calling into other functions
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
|
||||
// Create reporter(s) so we can route listings through them
|
||||
auto reporter = makeReporter(m_config.get());
|
||||
|
||||
// Handle list request
|
||||
if (list(*reporter, *m_config)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TestGroup tests { std::move(reporter), m_config.get() };
|
||||
auto const totals = tests.execute();
|
||||
|
||||
if( m_config->warnAboutNoTests() && totals.error == -1 )
|
||||
return 2;
|
||||
|
||||
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||
// the return value to 255 prevents false negative when some multiple
|
||||
// of 256 tests has failed
|
||||
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
|
||||
}
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
catch( std::exception& ex ) {
|
||||
Catch::cerr() << ex.what() << std::endl;
|
||||
return MaxExitCode;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_SESSION_HPP_INCLUDED
|
||||
#define CATCH_SESSION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Session : Detail::NonCopyable {
|
||||
public:
|
||||
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
void showHelp() const;
|
||||
void libIdentify();
|
||||
|
||||
int applyCommandLine( int argc, char const * const * argv );
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||
int applyCommandLine( int argc, wchar_t const * const * argv );
|
||||
#endif
|
||||
|
||||
void useConfigData( ConfigData const& configData );
|
||||
|
||||
template<typename CharT>
|
||||
int run(int argc, CharT const * const argv[]) {
|
||||
if (m_startupExceptions)
|
||||
return 1;
|
||||
int returnCode = applyCommandLine(argc, argv);
|
||||
if (returnCode == 0)
|
||||
returnCode = run();
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int run();
|
||||
|
||||
Clara::Parser const& cli() const;
|
||||
void cli( Clara::Parser const& newParser );
|
||||
ConfigData& configData();
|
||||
Config& config();
|
||||
private:
|
||||
int runInternal();
|
||||
|
||||
Clara::Parser m_cli;
|
||||
ConfigData m_configData;
|
||||
Detail::unique_ptr<Config> m_config;
|
||||
bool m_startupExceptions = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_SESSION_HPP_INCLUDED
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||
#define CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TagAlias {
|
||||
TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
|
||||
tag(_tag),
|
||||
lineInfo(_lineInfo)
|
||||
{}
|
||||
|
||||
std::string tag;
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||