Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ Current version tag: **5.1.0** (latest tag on the develop branch)
| VARIANT value | Define set | Backend | Source path |
|---------------|----------------|-----------|---------------------------------|
| `C` (default) | `-DUT_CUNIT` | CUnit 2.1-3 | `src/c_source/ut_cunit.c` |
| `CPP` | (none extra) | GTest 1.15.2 | `src/cpp_source/ut_gtest.cpp` |
| `CPP` | (none extra) | GTest + GMock 1.15.2 | `src/cpp_source/ut_gtest.cpp` |

When `UT_CUNIT` is defined, `ut.h` includes `ut_cunit.h`.
When `UT_CUNIT` is **not** defined (C++ path), `ut.h` includes `ut_gtest.h`.
When `UT_CUNIT` is **not** defined (C++ path), `ut.h` includes `ut_gtest.h` **and** `ut_gmock.h` (GoogleMock wrappers). The combined googletest distribution ships googlemock, so no extra download is needed.

---

Expand Down Expand Up @@ -165,7 +165,7 @@ All `_FATAL` macros record failure and **abort the current test**.

---

## 5. C++ Path API (ut_gtest.h) -- When VARIANT=CPP
## 5. C++ Path API (ut_gtest.h + ut_gmock.h) -- When VARIANT=CPP

### Test fixture class

Expand Down Expand Up @@ -238,6 +238,25 @@ Non-`_FATAL` use GTest `EXPECT_*` (continue on failure).

> Note: the C++ path does **not** define the `_MSG`/`_LOG` macro family or the `UT_ASSERT_PTR_*` macros from the C path, and has no plain `UT_ASSERT` (use `UT_ASSERT_TRUE`). Conversely, `UT_ASSERT_LESS`, `UT_ASSERT_GREATER`, the throw macros, and the floating-point and ignore-case string macros exist only in the C++ path.

### Mocking macros (C++ path -- GoogleMock backend)

`ut_gmock.h` wraps GoogleMock so C++ tests can mock an interface under test using `UT_`-prefixed macros, without including `<gmock/gmock.h>` directly. It is pulled in automatically by `ut.h` on the C++ path. Mock verification is active because the test runner calls `::testing::InitGoogleMock` — an unmet `UT_MOCK_EXPECT_CALL` fails the run.

| Macro | Maps to | Purpose |
|---|---|---|
| `UT_MOCK_METHOD(ret, name, (args), (specs))` | `MOCK_METHOD` | Declare a mocked method in a mock class |
| `UT_MOCK_EXPECT_CALL(mock, call)` | `EXPECT_CALL` | Set an expectation (chain `.Times()`, `.WillOnce()`, ...) |
| `UT_MOCK_ON_CALL(mock, call)` | `ON_CALL` | Set default behaviour without a count expectation |
| `UT_MOCK_NICE/UT_MOCK_NAGGY/UT_MOCK_STRICT(type)` | `NiceMock/NaggyMock/StrictMock` | Control uninteresting-call strictness |
| `UT_MOCK_ANY`, `UT_MOCK_EQ/NE/GT/GE/LT/LE(v)`, `UT_MOCK_NOTNULL`, `UT_MOCK_ISNULL`, `UT_MOCK_STR_EQ(v)`, `UT_MOCK_BETWEEN(lo,hi)` | `::testing::_`, `Eq/Ne/Gt/...`, matchers | Argument matchers |
| `UT_MOCK_RETURN(v)`, `UT_MOCK_RETURN_REF(v)`, `UT_MOCK_DO_DEFAULT`, `UT_MOCK_INVOKE(f)`, `UT_MOCK_SET_ARG_POINTEE(N,v)`, `UT_MOCK_DO_ALL(...)`, `UT_MOCK_THROW(e)` | `::testing::Return/Invoke/...` | Actions |
| `UT_MOCK_AT_LEAST(n)`, `UT_MOCK_AT_MOST(n)`, `UT_MOCK_EXACTLY(n)`, `UT_MOCK_ANY_NUMBER` | `::testing::AtLeast/...` | Cardinalities (argument to `.Times()`) |
| `UT_MOCK_VERIFY_AND_CLEAR(mock)` | `Mock::VerifyAndClearExpectations` | Verify expectations mid-test |

Mock classes register and run like any other gtest suite (`UT_ADD_TEST_TO_GROUP` / `UT_ADD_TEST`). See `tests/src/cpp_source/ut_test_gmock.cpp` for a worked interface-mock example.

**Autogeneration.** `scripts/autogenerate_gmock.sh -f <interface.h> [-c <Class>] [-o <dir>]` parses the pure-virtual methods of a C++ interface header and emits a matching mock (`mock_<class>.h`, one `UT_MOCK_METHOD` per virtual) plus a gtest test skeleton (`test_<class>.cpp`). It handles standard single-line `virtual ... = 0;` declarations; wrap comma-bearing template return types in a typedef. (GoogleMock's own `gmock_gen.py` was removed from googletest by 1.15.2, so generation is provided by ut-core.)

---

## 6. KVP Profile System (ut_kvp_profile.h)
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,12 @@ else # GTEST case
SRC_DIRS += $(UT_CORE_DIR)/src
EXCLUDE_DIRS = $(SRCDIR)/c_source
GTEST_SRC = $(FRAMEWORK_DIR)/gtest/$(TARGET)/googletest-1.15.2
INC_DIRS += $(GTEST_SRC)/googletest/include $(UT_CORE_DIR)/src/cpp_source $(UT_CORE_DIR)/src
INC_DIRS += $(GTEST_SRC)/googletest/include $(GTEST_SRC)/googlemock/include $(UT_CORE_DIR)/src/cpp_source $(UT_CORE_DIR)/src
TEST_LIB_DIR = $(UT_CORE_DIR)/build/$(TARGET)/cpp_libs/lib/
XLDFLAGS += $(YLDFLAGS) $(LDFLAGS) -L$(UT_CONTROL)/build/$(TARGET)/lib -L$(TEST_LIB_DIR) -lgtest_main -lgtest -lut_control -lpthread -lm
# Link gmock_main (not gtest_main) as the fallback main() so a downstream
# project without its own main() still gets InitGoogleMock (gmock flags +
# verification), matching the init performed in UTTestRunner.
XLDFLAGS += $(YLDFLAGS) $(LDFLAGS) -L$(UT_CONTROL)/build/$(TARGET)/lib -L$(TEST_LIB_DIR) -lgmock_main -lgmock -lgtest -lut_control -lpthread -lm

# Source files
SRCS := $(shell find $(SRC_DIRS) -type f \( -name '*.cpp' -o -name '*.c' \) | grep -v "$(EXCLUDE_DIRS)")
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ make VARIANT=CPP

This will build the following directories `src/*.c`, in addition to core functions from `ut-core/src/cpp_source` and linking against libraries in `ut-core/framework`

The CPP variant links both GoogleTest and **GoogleMock** (both ship in the pinned googletest distribution). Tests can mock a C++ interface using the `UT_MOCK_METHOD` / `UT_MOCK_EXPECT_CALL` wrappers in `include/ut_gmock.h` (pulled in automatically by `ut.h`); see `tests/src/cpp_source/ut_test_gmock.cpp` for a worked example.

`skeletons/src` - will be included in the linux build to enable stubs to compile against

### Build the target `arm` environment with CPP language
Expand Down
1 change: 1 addition & 0 deletions include/ut.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ void UT_regsiter_test_cleanup_function( UT_test_suite_t *pSuite, UT_TestCleanupF
#else

#include <ut_gtest.h>
#include <ut_gmock.h>

#endif

Expand Down
163 changes: 163 additions & 0 deletions include/ut_gmock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2026 RDK Management
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** @brief
* UT Unit wrapper to the GoogleMock (gmock) framework.
*
* Hides the functionality of gmock behind UT_-prefixed macros, so tests can
* create and use mocks of C++ interfaces without including <gmock/gmock.h>
* directly. Companion to ut_gtest.h.
*/
/** @addtogroup UT_GMOCK
* @{
*/

#ifndef __UT_GMOCK_H
#define __UT_GMOCK_H
Comment thread
Ulrond marked this conversation as resolved.

#include <gmock/gmock.h>

/**
* @brief Declares a mocked method inside a mock class.
*
* Thin wrapper over gmock's MOCK_METHOD. Use the modern 3- or 4-argument form:
* UT_MOCK_METHOD(return_type, method_name, (args...))
* UT_MOCK_METHOD(return_type, method_name, (args...), (const, override))
*
* @code
* class MockDriver : public IDriver {
* public:
* UT_MOCK_METHOD(int, open, (const char *path), (override));
* UT_MOCK_METHOD(bool, read, (int fd, void *buf, size_t len), (override));
* };
* @endcode
*/
#define UT_MOCK_METHOD(...) MOCK_METHOD(__VA_ARGS__)

/**
* @brief Sets an expectation on a mock method call.
*
* Wrapper over gmock's EXPECT_CALL. Chain the usual clauses
* (.Times(), .WillOnce(), .WillRepeatedly(), .With(), ...).
*
* @code
* UT_MOCK_EXPECT_CALL(mock, open(UT_MOCK_ANY)).Times(UT_MOCK_AT_LEAST(1)).WillOnce(UT_MOCK_RETURN(3));
* @endcode
*/
#define UT_MOCK_EXPECT_CALL(mock_object, call) EXPECT_CALL(mock_object, call)

/**
* @brief Sets the default behaviour of a mock method (no expectation on count).
*/
#define UT_MOCK_ON_CALL(mock_object, call) ON_CALL(mock_object, call)

/* ---- Mock strictness wrappers ------------------------------------------- */

/**
* @brief A mock whose uninteresting calls are silently ignored.
*/
#define UT_MOCK_NICE(type) ::testing::NiceMock<type>

/**
* @brief A mock whose uninteresting calls produce a warning (gmock default).
*/
#define UT_MOCK_NAGGY(type) ::testing::NaggyMock<type>

/**
* @brief A mock whose uninteresting calls are treated as failures.
*/
#define UT_MOCK_STRICT(type) ::testing::StrictMock<type>

/* ---- Common matchers (argument matching in EXPECT_CALL) ------------------ */

/*
* NOTE: these UT_MOCK_* matchers are NOT the UT_ASSERT_* assertions from
* ut_gtest.h. A matcher (e.g. UT_MOCK_LT(5)) describes which argument values
* satisfy an expectation and is used *inside*
* UT_MOCK_EXPECT_CALL(mock, foo(UT_MOCK_LT(5))). An assertion (e.g.
* UT_ASSERT_LESS(a, b)) checks a value and records pass/fail. The UT_MOCK_
* prefix makes the distinction explicit: everything in this header is UT_MOCK_*.
*/

/** @brief Matches any argument value. */
#define UT_MOCK_ANY ::testing::_
/** @brief Matches an argument equal to @p value. */
#define UT_MOCK_EQ(value) ::testing::Eq(value)
/** @brief Matches an argument not equal to @p value. */
#define UT_MOCK_NE(value) ::testing::Ne(value)
/** @brief Matches an argument greater than @p value. */
#define UT_MOCK_GT(value) ::testing::Gt(value)
/** @brief Matches an argument greater than or equal to @p value. */
#define UT_MOCK_GE(value) ::testing::Ge(value)
/** @brief Matches an argument less than @p value. */
#define UT_MOCK_LT(value) ::testing::Lt(value)
/** @brief Matches an argument less than or equal to @p value. */
#define UT_MOCK_LE(value) ::testing::Le(value)
/** @brief Matches a non-null pointer argument. */
#define UT_MOCK_NOTNULL ::testing::NotNull()
/** @brief Matches a null pointer argument. */
#define UT_MOCK_ISNULL ::testing::IsNull()
/** @brief Matches a C-string argument equal to @p value. */
#define UT_MOCK_STR_EQ(value) ::testing::StrEq(value)
/** @brief Matches an argument within [@p lo, @p hi]. */
#define UT_MOCK_BETWEEN(lo, hi) ::testing::AllOf(::testing::Ge(lo), ::testing::Le(hi))

/* ---- Common actions (what a mocked call does) --------------------------- */

/** @brief Returns @p value from the mocked call. */
#define UT_MOCK_RETURN(value) ::testing::Return(value)
/** @brief Returns a reference to @p value from the mocked call. */
#define UT_MOCK_RETURN_REF(value) ::testing::ReturnRef(value)
/** @brief Performs the method's default action (e.g. the ON_CALL default, or
* gmock's built-in default return for the type). Note: a mocked method with
* no action already returns a default-constructed value automatically. */
#define UT_MOCK_DO_DEFAULT ::testing::DoDefault()
/** @brief Invokes @p f (a callable) with the mocked call's arguments. */
#define UT_MOCK_INVOKE(f) ::testing::Invoke(f)
/** @brief Writes @p value through the pointer/reference at argument index @p N. */
#define UT_MOCK_SET_ARG_POINTEE(N, value) ::testing::SetArgPointee<N>(value)
/** @brief Performs all of the supplied actions in order. */
#define UT_MOCK_DO_ALL(...) ::testing::DoAll(__VA_ARGS__)
/** @brief Throws @p exception from the mocked call. */
#define UT_MOCK_THROW(exception) ::testing::Throw(exception)

/* ---- Cardinalities (arguments to .Times()) ------------------------------ */

/** @brief Cardinality: at least @p n calls. */
#define UT_MOCK_AT_LEAST(n) ::testing::AtLeast(n)
/** @brief Cardinality: at most @p n calls. */
#define UT_MOCK_AT_MOST(n) ::testing::AtMost(n)
/** @brief Cardinality: exactly @p n calls. */
#define UT_MOCK_EXACTLY(n) ::testing::Exactly(n)
/** @brief Cardinality: any number of calls (including zero). */
#define UT_MOCK_ANY_NUMBER ::testing::AnyNumber()

/**
* @brief Verifies and clears all expectations on @p mock immediately.
*
* Returns true if all expectations were satisfied. Normally verification runs
* automatically when the mock is destroyed (gmock is initialised via
* ::testing::InitGoogleMock in the UT test runner), but this is useful to
* assert expectations mid-test.
*/
#define UT_MOCK_VERIFY_AND_CLEAR(mock) ::testing::Mock::VerifyAndClearExpectations(&(mock))

#endif /* UT -> GMOCK - Wrapper */
Comment thread
Ulrond marked this conversation as resolved.

/** @} */
Loading