diff --git a/.github/tools/coverage.sh b/.github/tools/coverage.sh new file mode 100755 index 00000000..508521ec --- /dev/null +++ b/.github/tools/coverage.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +# +# Runs unit + component tests with code coverage and generates HTML + +# Cobertura XML reports. +# +# Prerequisites (install once): +# sudo apt-get install -y lcov +# pipx install lcov-cobertura +# +# Usage: +# .github/tools/coverage.sh [] [--config ] [--output-dir ] +# +# Options: +# Bazel target to collect coverage for (default: //score/...) +# --config Bazel config to use (default: time-x86_64-linux) +# --output-dir Directory for generated reports (default: cpp_coverage) + +set -euo pipefail + +OUTPUT_DIR="cpp_coverage" +BAZEL_CONFIG="time-x86_64-linux" +BAZEL_TARGET="${1:-//score/...}" + +# Consume the target argument if it was provided positionally +[[ $# -gt 0 && "$1" != --* ]] && shift + +while [[ $# -gt 0 ]]; do + case "$1" in + --config) + BAZEL_CONFIG="$2" + shift 2 + ;; + --output-dir) + OUTPUT_DIR="$2" + shift 2 + ;; + --target) + BAZEL_TARGET="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +echo "==> Running tests with coverage..." +bazel coverage --config="${BAZEL_CONFIG}" -- "${BAZEL_TARGET}" + +OUTPUT_PATH="$(bazel info output_path)" +EXEC_ROOT="$(bazel info execution_root)" +DAT_FILE="${OUTPUT_PATH}/_coverage/_coverage_report.dat" + +echo "==> Generating HTML report in '${OUTPUT_DIR}'..." +genhtml "${DAT_FILE}" \ + --output-directory="${OUTPUT_DIR}" \ + --show-details \ + --source-directory="${EXEC_ROOT}" \ + --legend \ + --function-coverage \ + --branch-coverage + +echo "==> Generating Cobertura XML report at '${OUTPUT_DIR}/coverage.xml'..." +lcov_cobertura "${DAT_FILE}" \ + --base-dir "${EXEC_ROOT}" \ + --output "${OUTPUT_DIR}/coverage.xml" + +echo "" +echo "Coverage reports written to '${OUTPUT_DIR}/'." +echo " HTML: ${OUTPUT_DIR}/index.html" +echo " Cobertura: ${OUTPUT_DIR}/coverage.xml" diff --git a/BUILD b/BUILD index e994a4a1..319ef866 100644 --- a/BUILD +++ b/BUILD @@ -92,3 +92,24 @@ use_format_targets(languages = [ "yaml", "cpp", ]) + +# Aggregated component-test suite. Component tests exercise a clock facade +# (Clock) together with a mocked backend, i.e. more than one unit of code +# but without a real driver. Run with: +# bazel test --config=time-x86_64-linux //:component_tests +test_suite( + name = "component_tests", + tests = [ + "//score/time/high_res_steady_time/src:high_res_steady_clock_test", + "//score/time/steady_time/src:steady_clock_test", + "//score/time/system_time/src:system_clock_test", + "//score/time/vehicle_time/src:vehicle_clock_test", + ], + visibility = ["//visibility:public"], +) + +# Unit tests: every cc_test under //score/... is already tagged "unit", +# so `bazel test //score/...` is the canonical unit-tests invocation. +# No aggregate test_suite is needed here — a `test_suite` in a top-level +# BUILD file cannot use `//score/...` as an element of its `tests` +# attribute (package wildcards are rejected). diff --git a/docs/index.rst b/docs/index.rst index d099c763..16cfe6e5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -44,6 +44,7 @@ For a detailed concept and architectural design, please refer to the :doc:`time_ features/index module/index + quality_pack Project Layout diff --git a/docs/quality_pack.rst b/docs/quality_pack.rst new file mode 100644 index 00000000..2f52f4ab --- /dev/null +++ b/docs/quality_pack.rst @@ -0,0 +1,149 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +Quality Pack Targets +#################### + +The ``score_time`` module plugs into the Score docs-as-code +dashboards and quality gates as described in the upstream how-to: +https://eclipse-score.github.io/docs-as-code/main/how-to/dashboards_and_quality_gates.html. + +The Bazel targets below are the ones consumed by CI to produce +dashboard artefacts and to enforce traceability thresholds. + +Unit tests +========== + +- **Tag:** ``unit`` (already carried by every ``cc_test`` under + ``//score/...``). +- **Command:** ``bazel test --config=time-x86_64-linux //score/...`` — this + runs the full unit-test set because every ``cc_test`` in the tree + carries the ``unit`` tag. +- **Results:** JUnit XML and stdout log per test target under + ``bazel-testlogs///{test.log,test.xml}``. + +Component tests +=============== + +Component tests exercise a clock facade (``Clock``) together with a +mocked backend via ``ScopedClockOverride`` — the seam between the framework +layer and a domain-specific backend is covered end to end. + +- **Tag:** ``component``. +- **Aggregate target:** ``//:component_tests``. +- **Command:** ``bazel test --config=time-x86_64-linux //:component_tests``. +- **Included tests (existing tests reclassified, not new ones):** + + - ``//score/time/vehicle_time/src:vehicle_clock_test`` + - ``//score/time/high_res_steady_time/src:high_res_steady_clock_test`` + - ``//score/time/system_time/src:system_clock_test`` + - ``//score/time/steady_time/src:steady_clock_test`` + +- **Results:** JUnit XML and stdout log per test target under + ``bazel-testlogs///{test.log,test.xml}``. + +Code coverage +============= + +- **Command:** ``.github/tools/coverage.sh //score/... --config time-x86_64-linux``. +- **Underlying target:** ``bazel coverage`` with the ``coverage`` config + from ``.bazelrc``. +- **Results:** HTML report at ``cpp_coverage/index.html`` and Cobertura + XML at ``cpp_coverage/coverage.xml``. The raw ``lcov`` data lives under + ``$(bazel info output_path)/_coverage/_coverage_report.dat``. +- **CI:** ``.github/workflows/code-coverage.yml`` runs the reusable + ``eclipse-score/cicd-workflows`` coverage workflow with the same + target and config and enforces the configured minimum coverage + threshold. + +Requirements traceability (dashboards + gate) +============================================= + +Component requirements live alongside the module under +``score/time/docs/requirements/requirements.rst`` and use the Score +metamodel ``comp_req::`` directive. Feature-level requirements +(``feat_req::``) belong to the upstream ``eclipse-score/score`` repo and +are consumed here via the external needs.json feed. Source-code and +test-code links are consumed by ``score_docs_as_code``: + +- **Source-code markers** — in the C++ implementation: + + .. code-block:: cpp + + // # req-Id: comp_req__vehicle_time__snapshot + Snapshot Now() { ... } + + The leading ``// #`` is intentional; the linker regex looks for the + literal token ``# req-Id:`` and this is the neutral C++ form. The + files that carry markers are collected in + ``//score/time/vehicle_time/src:requirement_marked_sources`` (a + ``filegroup``) and passed to the root ``docs()`` macro via its + ``scan_code`` attribute. + +- **Test-code links** — use GoogleTest ``RecordProperty`` inside each + linked test body: + + .. code-block:: cpp + + TEST(VehicleClockTest, InitForwardsToBackend) + { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__vehicle_time__lifecycle"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "requirements-analysis"); + ::testing::Test::RecordProperty("Description", "…"); + ... + } + + The properties land in ``bazel-testlogs/.../test.xml`` and are read by + ``score_source_code_linker`` when docs are built. + +- **Bazel targets:** + + - ``//:needs_json`` — needs.json produced by Sphinx-Needs. + - ``//:metrics_json`` — traceability metrics extracted from needs.json. + - ``//:traceability_gate`` — enforces coverage thresholds. + +- **Local flow** (order matters — the gate reads ``bazel-testlogs`` for + test links): + + .. code-block:: bash + + bazel test --config=time-x86_64-linux //:component_tests //score/... + bazel run //:docs + bazel run //:traceability_gate -- \ + --metrics-json "$(pwd)/_build/metrics.json" \ + --need-type comp_req \ + --min-req-code 100 \ + --min-req-test 62 \ + --min-req-fully-linked 62 \ + --min-tests-linked 1 + + Current baseline (component requirements only): + + ========================= =============== + Metric Value + ========================= =============== + Requirements with source 8/8 (100.0%) + Requirements with test 5/8 (62.5%) + Requirements fully linked 5/8 (62.5%) + Tests linked to reqs 5/318 (1.6%) + ========================= =============== + +.. note:: + + The exact target names and result folders above are the current + convention for this repository. They can be renamed together with + ``@Zwinkau Andreas (ETAS-ECM ESY3)`` if a project-wide naming scheme + is agreed upon; the CI workflows in ``.github/workflows`` reference + these targets directly and would need to move in lockstep. diff --git a/score/time/BUILD b/score/time/BUILD index 7f707a4b..7f9d894f 100644 --- a/score/time/BUILD +++ b/score/time/BUILD @@ -17,6 +17,13 @@ load("@score_docs_as_code//:docs.bzl", "docs_bundle") docs_bundle( name = "docs_bundle", + code_targets = [ + "//score/time/clock/src:requirement_marked_sources", + "//score/time/high_res_steady_time/src:requirement_marked_sources", + "//score/time/steady_time/src:requirement_marked_sources", + "//score/time/system_time/src:requirement_marked_sources", + "//score/time/vehicle_time/src:requirement_marked_sources", + ], source_dir = "docs", visibility = ["//visibility:public"], ) diff --git a/score/time/clock/src/BUILD b/score/time/clock/src/BUILD index ebf6e914..95980ed6 100644 --- a/score/time/clock/src/BUILD +++ b/score/time/clock/src/BUILD @@ -14,6 +14,14 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +# Source files carrying `// # req-Id:` markers, exposed to +# //score/time:docs_bundle via its code_targets attribute. +filegroup( + name = "requirement_marked_sources", + srcs = ["clock.h"], + visibility = ["//visibility:public"], +) + cc_library( name = "clock_core", hdrs = [ diff --git a/score/time/clock/src/clock.h b/score/time/clock/src/clock.h index 9b4ab98e..16b74651 100644 --- a/score/time/clock/src/clock.h +++ b/score/time/clock/src/clock.h @@ -84,6 +84,7 @@ class Clock using Snapshot = typename Trait::Snapshot; /// @brief Returns the process-wide @c Clock handle. + // # req-Id: comp_req__time__unified_clock_facade [[nodiscard]] static Clock GetInstance() noexcept { std::lock_guard lock{instance_guard_}; @@ -101,6 +102,7 @@ class Clock } /// @brief Returns the current clock snapshot (time_point + optional status). + // # req-Id: comp_req__time__snapshot_with_status [[nodiscard]] Snapshot Now() const noexcept { return Trait::CallNow(*impl_); @@ -137,6 +139,7 @@ class Clock /// Calling this on an always-ready clock (HighResSteadyTime, steady_clock) is a compile error. /// /// @return @c true if the backend is ready; @c false on failure. + // # req-Id: comp_req__time__explicit_lifecycle template ::value, bool> = true> [[nodiscard]] bool Init() noexcept { @@ -147,6 +150,7 @@ class Clock /// /// Only available for clock domains that require a readiness check (e.g. VehicleTime). /// Calling this on an always-available clock (HighResSteadyTime, steady_clock) is a compile error. + // # req-Id: comp_req__time__explicit_lifecycle template ::value, int> = 0> [[nodiscard]] bool IsAvailable() const noexcept { @@ -162,6 +166,7 @@ class Clock /// @param until Steady-clock deadline after which the wait is abandoned. /// /// @return @c true if the resource became available before the deadline. + // # req-Id: comp_req__time__explicit_lifecycle template ::value, int> = 0> [[nodiscard]] bool WaitUntilAvailable(const score::cpp::stop_token& token, std::chrono::steady_clock::time_point until) const noexcept diff --git a/score/time/docs/requirements/requirements.rst b/score/time/docs/requirements/requirements.rst index 6589d6db..b643e999 100644 --- a/score/time/docs/requirements/requirements.rst +++ b/score/time/docs/requirements/requirements.rst @@ -13,96 +13,135 @@ # ******************************************************************************* Component Time Requirements -############################ +########################### .. document:: Time Requirements :id: doc__time_requirements - :status: draft + :status: valid :version: 1 - :safety: ASIL_B + :safety: QM :security: NO :realizes: wp__requirements_comp[version==1] - :tags: time - -.. note:: - Work in progress: structure, titles, and needs IDs only. Content and req/comp/feat traceability links to follow in later PRs. - -.. attention:: - The above directive must be updated according to your Component. - - - Adjust ``status`` to be ``valid`` - - Adjust ``safety``, ``security`` and ``tags`` according to your needs - - -=================================================================== + :tags: requirements, time Functional Requirements ----------------------- -.. code-block:: rst - - .. comp_req:: Some Title - :id: comp_req__time__some_title - :reqtype: Functional - :security: NO - :safety: ASIL_B - :derived_from: feat_req__time__example_req - :status: invalid - :version: 1 - :satisfied_by: comp__time +.. comp_req:: Unified clock facade across time domains + :id: comp_req__time__unified_clock_facade + :reqtype: Interface + :security: NO + :safety: QM + :derived_from: feat_req__time__high_prec_clock_api, feat_req__time__monotonic_clock_api, feat_req__time__abs_base_api, feat_req__time__vehicle_time_time_api + :status: valid + :version: 1 + :satisfied_by: comp__time - The Component shall do xyz to another component to bring it to this condition at this time + The Component shall provide a single type-safe accessor for all supported + clock domains that prevents mixing time values from different domains by + rejecting domain-mismatched operations at compile time when accessing + time snapshots. - Note: (optional, not to be verified) +.. comp_req:: Immutable snapshot with quality metadata + :id: comp_req__time__snapshot_with_status + :reqtype: Functional + :security: NO + :safety: QM + :derived_from: feat_req__time__vehicle_time_time_api + :status: valid + :version: 1 + :satisfied_by: comp__time -.. attention:: - The above directive must be updated according to your component requirements. + The Component shall return a single immutable value that bundles + the timepoint with the domain's synchronization and quality + metadata, so callers observe state that cannot change after + creation and can determine time validity without a separate + status query. - - Replace the example content by the real content for your first requirement - - Set ``derived_from`` with links to Feature requirements - - Set ``satisfied_by`` with a link to the right Component id - - Set ``safety`` and ``security`` to the right value - - Set the status to valid and start the review/merge process - - Add other needed requirements for your component +.. comp_req:: Explicit lifecycle for backends that need it + :id: comp_req__time__explicit_lifecycle + :reqtype: Functional + :security: NO + :safety: QM + :derived_from: feat_req__time__vehicle_time_ctrl_flow + :status: valid + :version: 1 + :satisfied_by: comp__time -Assumption of Use Requirements ------------------------------- + The Component shall provide initialization, availability-check, and + availability-wait operations for clock domains that depend on external + resources, and shall cause compilation failure when those operations + are invoked on clock domains that are always ready. -.. aou_req:: Next Title - :id: aou_req__time__next_title - :reqtype: Process +.. comp_req:: VehicleClock returns snapshot with status + :id: comp_req__vehicle_time__snapshot + :reqtype: Functional :security: NO - :safety: ASIL_B - :status: invalid + :safety: QM + :derived_from: feat_req__time__vehicle_time_time_api + :status: valid :version: 1 + :satisfied_by: comp__time - The Component User shall do xyz to use the component safely/securely + The Component shall read the vehicle time timepoint and its status + atomically from the backend within a single backend operation, so + downstream callers observe consistent time and status values. -Environmental Requirements --------------------------- +.. comp_req:: VehicleClock lifecycle operations + :id: comp_req__vehicle_time__lifecycle + :reqtype: Functional + :security: NO + :safety: QM + :derived_from: feat_req__time__vehicle_time_ctrl_flow + :status: valid + :version: 1 + :satisfied_by: comp__time -.. aou_req:: Another Title - :id: aou_req__time__another - :reqtype: Process + The Component shall delegate initialization and + availability checks to the backend and shall report backend + init failure and availability-wait timeouts to the caller without + blocking indefinitely. + +.. comp_req:: HighResSteadyClock always-ready snapshot + :id: comp_req__high_res_steady_time__snapshot + :reqtype: Functional :security: NO - :safety: ASIL_B - :status: invalid + :safety: QM + :derived_from: feat_req__time__high_prec_clock_api + :status: valid :version: 1 - :tags: environment + :satisfied_by: comp__time - The Component shall only be used in a xyz environment to ensure its proper functioning. + The Component shall provide monotonic high-resolution time snapshots + without requiring initialization, and shall cause compilation failure + when initialization or availability operations are invoked on the + high-resolution steady time domain. -Hints ------ +.. comp_req:: SteadyClock always-ready snapshot + :id: comp_req__steady_time__snapshot + :reqtype: Functional + :security: NO + :safety: QM + :derived_from: feat_req__time__monotonic_clock_api + :status: valid + :version: 1 + :satisfied_by: comp__time + + The Component shall provide monotonic steady time snapshots without + requiring initialization. -.. attention:: - The above directives must be updated according to your feature requirements. +.. comp_req:: SystemClock always-ready snapshot + :id: comp_req__system_time__snapshot + :reqtype: Functional + :security: NO + :safety: QM + :derived_from: feat_req__time__abs_base_api + :status: valid + :version: 1 + :satisfied_by: comp__time - - Replace the example content by the real content for your first requirement (according to :need:`gd_guidl__req_engineering`) - - Set ``safety`` and ``security`` to the right value (ASIL B/QM; YES/NO) - - Set ``reqtype`` with a link to the right value () - - Add other needed requirements for your feature - - Set ``status`` to ``valid`` and start the review/merge process + The Component shall provide wall-clock time snapshots without + requiring initialization. .. needextend:: is_external == False and "time" in id :+tags: time diff --git a/score/time/high_res_steady_time/src/BUILD b/score/time/high_res_steady_time/src/BUILD index 99bd56a6..f25f1e60 100644 --- a/score/time/high_res_steady_time/src/BUILD +++ b/score/time/high_res_steady_time/src/BUILD @@ -15,6 +15,14 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") load("@score_baselibs//third_party/itf:py_unittest_qnx_test.bzl", "py_unittest_qnx_test") +# Source files carrying `// # req-Id:` markers, exposed to +# //score/time:docs_bundle via its code_targets attribute. +filegroup( + name = "requirement_marked_sources", + srcs = ["high_res_steady_clock.cpp"], + visibility = ["//visibility:public"], +) + cc_library( name = "high_res_steady_clock", srcs = ["high_res_steady_clock.cpp"], @@ -75,6 +83,7 @@ cc_test( srcs = ["high_res_steady_clock_adapter_test.cpp"], features = COMPILER_WARNING_FEATURES, tags = [ + "component", "exclusive", "unit", ], diff --git a/score/time/high_res_steady_time/src/high_res_steady_clock.cpp b/score/time/high_res_steady_time/src/high_res_steady_clock.cpp index c1945450..b39c7972 100644 --- a/score/time/high_res_steady_time/src/high_res_steady_clock.cpp +++ b/score/time/high_res_steady_time/src/high_res_steady_clock.cpp @@ -18,6 +18,7 @@ namespace score namespace time { +// # req-Id: comp_req__high_res_steady_time__snapshot ClockTraits::Snapshot ClockTraits::CallNow(const Backend& impl) noexcept { return impl.Now(); diff --git a/score/time/high_res_steady_time/src/high_res_steady_clock_adapter_test.cpp b/score/time/high_res_steady_time/src/high_res_steady_clock_adapter_test.cpp index 2ad6ce90..7f403421 100644 --- a/score/time/high_res_steady_time/src/high_res_steady_clock_adapter_test.cpp +++ b/score/time/high_res_steady_time/src/high_res_steady_clock_adapter_test.cpp @@ -28,6 +28,12 @@ namespace time TEST(HighResSteadyClockTest, NowReturnsTimepointSuitableForDurationArithmetic) { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__high_res_steady_time__snapshot"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "requirements-analysis"); + ::testing::Test::RecordProperty("Description", + "HighResSteadyClock::Now returns a monotonic snapshot without requiring Init."); + auto mock = std::make_shared(); test_utils::ScopedClockOverride guard{mock}; diff --git a/score/time/steady_time/src/BUILD b/score/time/steady_time/src/BUILD index bc817931..92a8380c 100644 --- a/score/time/steady_time/src/BUILD +++ b/score/time/steady_time/src/BUILD @@ -14,6 +14,14 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +# Source files carrying `// # req-Id:` markers, exposed to +# //score/time:docs_bundle via its code_targets attribute. +filegroup( + name = "requirement_marked_sources", + srcs = ["steady_clock.cpp"], + visibility = ["//visibility:public"], +) + cc_library( name = "steady_clock", srcs = ["steady_clock.cpp"], @@ -60,6 +68,7 @@ cc_test( srcs = ["steady_clock_adapter_test.cpp"], features = COMPILER_WARNING_FEATURES, tags = [ + "component", "exclusive", "unit", ], diff --git a/score/time/steady_time/src/steady_clock.cpp b/score/time/steady_time/src/steady_clock.cpp index c4cc4490..c91822cb 100644 --- a/score/time/steady_time/src/steady_clock.cpp +++ b/score/time/steady_time/src/steady_clock.cpp @@ -18,6 +18,7 @@ namespace score namespace time { +// # req-Id: comp_req__steady_time__snapshot ClockTraits::Snapshot ClockTraits::CallNow( const Backend& impl) noexcept { diff --git a/score/time/steady_time/src/steady_clock_adapter_test.cpp b/score/time/steady_time/src/steady_clock_adapter_test.cpp index 39e22c32..50f15955 100644 --- a/score/time/steady_time/src/steady_clock_adapter_test.cpp +++ b/score/time/steady_time/src/steady_clock_adapter_test.cpp @@ -44,6 +44,12 @@ class SampleSteadyService TEST(SteadyClockTest, NowReturnsTimepointSuitableForDurationArithmetic) { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__steady_time__snapshot"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "requirements-analysis"); + ::testing::Test::RecordProperty("Description", + "SteadyClock::Now returns a snapshot backed by std::chrono::steady_clock."); + auto mock = std::make_shared(); test_utils::ScopedClockOverride guard{mock}; diff --git a/score/time/system_time/src/BUILD b/score/time/system_time/src/BUILD index 3917cbe7..4b897e4b 100644 --- a/score/time/system_time/src/BUILD +++ b/score/time/system_time/src/BUILD @@ -14,6 +14,14 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +# Source files carrying `// # req-Id:` markers, exposed to +# //score/time:docs_bundle via its code_targets attribute. +filegroup( + name = "requirement_marked_sources", + srcs = ["system_clock.cpp"], + visibility = ["//visibility:public"], +) + cc_library( name = "system_clock", srcs = ["system_clock.cpp"], @@ -60,6 +68,7 @@ cc_test( srcs = ["system_clock_adapter_test.cpp"], features = COMPILER_WARNING_FEATURES, tags = [ + "component", "exclusive", "unit", ], diff --git a/score/time/system_time/src/system_clock.cpp b/score/time/system_time/src/system_clock.cpp index 26f7901d..02a3b957 100644 --- a/score/time/system_time/src/system_clock.cpp +++ b/score/time/system_time/src/system_clock.cpp @@ -18,6 +18,7 @@ namespace score namespace time { +// # req-Id: comp_req__system_time__snapshot ClockTraits::Snapshot ClockTraits::CallNow( const Backend& impl) noexcept { diff --git a/score/time/system_time/src/system_clock_adapter_test.cpp b/score/time/system_time/src/system_clock_adapter_test.cpp index b000e645..d0260e45 100644 --- a/score/time/system_time/src/system_clock_adapter_test.cpp +++ b/score/time/system_time/src/system_clock_adapter_test.cpp @@ -44,6 +44,12 @@ class SampleSystemService TEST(SystemClockTest, NowReturnsTimepointSuitableForDurationArithmetic) { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__system_time__snapshot"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "requirements-analysis"); + ::testing::Test::RecordProperty("Description", + "SystemClock::Now returns a snapshot backed by std::chrono::system_clock."); + auto mock = std::make_shared(); test_utils::ScopedClockOverride guard{mock}; diff --git a/score/time/vehicle_time/src/BUILD b/score/time/vehicle_time/src/BUILD index 49ae57ef..6d9e59ff 100644 --- a/score/time/vehicle_time/src/BUILD +++ b/score/time/vehicle_time/src/BUILD @@ -14,6 +14,14 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +# Source files carrying `// # req-Id:` markers, exposed to the root +# docs() macro's scan_code attribute for source-code traceability. +filegroup( + name = "requirement_marked_sources", + srcs = ["vehicle_clock.cpp"], + visibility = ["//visibility:public"], +) + cc_library( name = "vehicle_clock", srcs = ["vehicle_clock.cpp"], @@ -65,6 +73,7 @@ cc_test( srcs = ["vehicle_clock_test.cpp"], features = COMPILER_WARNING_FEATURES, tags = [ + "component", "exclusive", "unit", ], diff --git a/score/time/vehicle_time/src/vehicle_clock.cpp b/score/time/vehicle_time/src/vehicle_clock.cpp index ee6af884..ef441677 100644 --- a/score/time/vehicle_time/src/vehicle_clock.cpp +++ b/score/time/vehicle_time/src/vehicle_clock.cpp @@ -41,21 +41,25 @@ std::ostringstream ClockStatus::PrintTo() const return oss; } +// # req-Id: comp_req__vehicle_time__snapshot ClockTraits::Snapshot ClockTraits::CallNow(const Backend& impl) noexcept { return impl.Now(); } +// # req-Id: comp_req__vehicle_time__lifecycle bool InitializationHook::CallInit(Backend& impl) noexcept { return impl.Init(); } +// # req-Id: comp_req__vehicle_time__lifecycle bool AvailabilityHook::CallIsAvailable(const Backend& impl) noexcept { return impl.IsAvailable(); } +// # req-Id: comp_req__vehicle_time__lifecycle bool AvailabilityHook::CallWaitUntilAvailable(const Backend& impl, const score::cpp::stop_token& token, std::chrono::steady_clock::time_point until) noexcept diff --git a/score/time/vehicle_time/src/vehicle_clock_test.cpp b/score/time/vehicle_time/src/vehicle_clock_test.cpp index 06bc9b00..91b9804e 100644 --- a/score/time/vehicle_time/src/vehicle_clock_test.cpp +++ b/score/time/vehicle_time/src/vehicle_clock_test.cpp @@ -52,6 +52,12 @@ class SampleVehicleService TEST(VehicleClockTest, NowReturnsSynchronizedStatusAndTimepoint) { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__vehicle_time__snapshot"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "equivalence-classes"); + ::testing::Test::RecordProperty("Description", + "VehicleClock::Now returns a snapshot combining backend timepoint and status."); + auto mock = std::make_shared(); test_utils::ScopedClockOverride guard{mock}; @@ -97,6 +103,11 @@ TEST(VehicleClockTest, NowIsReliableReturnsFalseWhenTimeoutSet) TEST(VehicleClockTest, InitForwardsToBackend) { + ::testing::Test::RecordProperty("FullyVerifies", "comp_req__vehicle_time__lifecycle"); + ::testing::Test::RecordProperty("TestType", "requirements-based"); + ::testing::Test::RecordProperty("DerivationTechnique", "requirements-analysis"); + ::testing::Test::RecordProperty("Description", "VehicleClock::Init delegates to the backend Init call."); + auto mock = std::make_shared(); test_utils::ScopedClockOverride guard{mock};