6#include <gmock/gmock.h>
7#include <gtest/gtest.h>
19using ::testing::InSequence;
20using ::testing::NiceMock;
21using ::testing::Return;
22using ::testing::StrictMock;
23using ::testing::Throw;
40dcp::DCPDeviceDescription MakeDeviceDescription()
44 dcp::DCPDeviceDescription info(
String2Mac(
"02:00:00:00:00:01"), {});
46 info.ip =
"192.168.0.10";
50std::optional<rpc::IOCRSetup> MakeIocrSetup()
52 std::optional<rpc::IOCRSetup> setup = rpc::IOCRSetup{};
53 setup->sendClockFactor = 32;
54 setup->reductionRatio = 32;
55 setup->watchdogFactor = 3;
66 auto mockRpc = std::make_unique<testing::NiceMock<rpc::MockRPCCon>>();
69 device = std::make_unique<ProfinetDevice>(
70 MakeDeviceDescription(),
77 std::unique_ptr<ProfinetDevice>
device;
84 EXPECT_CALL(*rpc, Connect(_,
false, _))
85 .WillOnce(Return(std::nullopt));
87 auto iocrSetup = MakeIocrSetup();
88 std::optional<rpc::ConnectResult> result;
91 EXPECT_CALL(*rpc, Connect(_,
true, iocrSetup))
92 .WillOnce(Return(result));
94 const auto& setup = iocrSetup.value();
95 EXPECT_THROW(device->StartCyclic(setup),
104 connectResult.outputFrameId = 0x8002;
106 auto mockController = std::make_unique<testing::NiceMock<cyclic::MockCyclicController>>();
109 testing::InSequence sequence;
111 EXPECT_CALL(*rpc, Connect(_,
false, _))
112 .WillOnce(Return(std::nullopt));
114 EXPECT_CALL(*rpc, Connect(_,
true, _))
115 .WillOnce(Return(connectResult));
117 EXPECT_CALL(*rpc,
PrmEnd())
118 .WillOnce(Return(
Bytes{}));
121 .WillOnce(Return(
Bytes{}));
125 auto result = device->StartCyclic(MakeIocrSetup().value(), 3, std::move(mockController));
136 EXPECT_CALL(*rpc, Connect(_,
false, _))
137 .WillOnce(Return(std::nullopt));
139 EXPECT_CALL(*rpc, Connect(_,
true, _))
140 .WillOnce(Return(connectResult));
142 EXPECT_THROW(device->StartCyclic(MakeIocrSetup().value()),
151 connectResult.outputFrameId = 0x8002;
153 EXPECT_CALL(*rpc, Connect(_,
false, _))
154 .WillOnce(Return(std::nullopt));
156 EXPECT_CALL(*rpc, Connect(_,
true, _))
157 .WillOnce(Return(connectResult));
159 EXPECT_CALL(*rpc,
PrmEnd())
160 .WillOnce(Return(
Bytes{}));
163 .WillOnce(Throw(std::runtime_error(
"timeout")));
165 auto mockController =
166 std::make_unique<testing::NiceMock<cyclic::MockCyclicController>>();
168 EXPECT_CALL(*mockController,
Start(_, _)).Times(0);
170 EXPECT_THROW(device->StartCyclic(MakeIocrSetup().value(), 3, std::move(mockController)),
173 EXPECT_TRUE(device->IsConnected());
182 connectResult.outputFrameId = 0x8002;
184 EXPECT_CALL(*rpc, Connect(_,
false, _))
185 .WillOnce(Return(std::nullopt));
187 EXPECT_CALL(*rpc, Connect(_,
true, _))
188 .WillOnce(Return(connectResult));
190 EXPECT_CALL(*rpc,
PrmEnd())
191 .WillOnce(Return(
Bytes{}));
194 .WillOnce(Throw(std::runtime_error(
"timeout")));
196 auto mockController =
197 std::make_unique<testing::NiceMock<cyclic::MockCyclicController>>();
199 EXPECT_CALL(*mockController,
Start(_, _)).Times(0);
201 EXPECT_THROW(device->StartCyclic(MakeIocrSetup().value(), 3, std::move(mockController)),
206TEST(StartCyclicOrderingTests, StartsRtAfterApplicationReadyWhenDisabled)
208 GTEST_SKIP() <<
"Current StartCyclic API has no start_rt_before_prm_end option.";
212TEST(StartCyclicOrderingTests, ApplicationReadyCanBeSkipped)
214 GTEST_SKIP() <<
"Current StartCyclic API has no confirm_application_ready option.";
224 connectResult.outputFrameId = 0x8002;
226 EXPECT_CALL(*rpc, Connect(_,
false, _))
227 .WillOnce(Return(std::nullopt));
229 EXPECT_CALL(*rpc, Connect(_,
true, _))
230 .WillOnce(Return(connectResult));
232 EXPECT_CALL(*rpc,
PrmEnd())
233 .WillOnce(Return(
Bytes{}));
236 .WillOnce(Return(
Bytes{}));
238 auto mockController =
239 std::make_unique<testing::NiceMock<cyclic::MockCyclicController>>();
241 EXPECT_CALL(*mockController,
Start(_, _));
243 auto result = device->StartCyclic(
244 MakeIocrSetup().value(),
246 std::move(mockController));
248 EXPECT_NE(result,
nullptr);
249 EXPECT_TRUE(device->IsConnected());
258 connectResult.outputFrameId = 0x8002;
260 EXPECT_CALL(*rpc, Connect(_,
false, _))
261 .WillOnce(Return(std::nullopt));
269 [](
const std::optional<rpc::IOCRSetup>& setup)
271 return setup.has_value() &&
272 setup->sendClockFactor == 32 &&
273 setup->reductionRatio == 32 &&
274 setup->watchdogFactor == 3;
276 .WillOnce(Return(connectResult));
278 EXPECT_CALL(*rpc,
PrmEnd())
279 .WillOnce(Return(
Bytes{}));
282 .WillOnce(Return(
Bytes{}));
284 auto mockController =
285 std::make_unique<testing::NiceMock<cyclic::MockCyclicController>>();
287 EXPECT_CALL(*mockController,
Start(_, _));
290 MakeIocrSetup().value(),
292 std::move(mockController));
296TEST(StartCyclicArHandlingTests, ReleasesExistingArBeforeNewConnect)
298 GTEST_SKIP() <<
"Current StartCyclic uses EnsureConnected() and reuses an existing AR.";
303TEST(StartCyclicArHandlingTests, StopsAlarmListenerBeforeReplacingAr)
305 GTEST_SKIP() <<
"Current StartCyclic does not replace an existing AR.";
310TEST(StartCyclicRollbackTests, PrmEndFailureRollsBack)
312 GTEST_SKIP() <<
"Current StartCyclic has no rollback path.";
317TEST(StartCyclicRollbackTests, MissingCyclicResultRollsBack)
319 GTEST_SKIP() <<
"Requires injectable RPCCon test seam.";
324TEST(StartCyclicRollbackTests, ApplicationReadyFailureStopsStartedRt)
326 GTEST_SKIP() <<
"Current StartCyclic starts RT only after ApplicationReady.";
331TEST(StartCyclicRollbackTests, ReleaseFailureDoesNotMaskOriginalError)
333 GTEST_SKIP() <<
"Current StartCyclic has no explicit rollback/release path.";
std::unique_ptr< ProfinetDevice > device
Google Mock implementation of the IRPCCon RPC connection interface.
High-level PROFINET device interface and device lifecycle management.
Google Mock implementation of the cyclic PROFINET controller interface.
Google Mock implementation of the IRPCCon PROFINET RPC connection interface.
TEST_F(DeviceTest, ParseMacAcceptsColonDashAndDotSeparators)
TEST(DeviceMoveTests, MoveConstructionDisconnectsSource)
constexpr MacAddress kControllerMac
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
MacAddress String2Mac(const std::string &macStr)
Parse a colon-separated MAC address string.
@ ApplicationReady
Application Ready command.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Result of a successful RPCCon::Connect() that also established cyclic IO.
std::uint16_t inputFrameId
Frame ID assigned to the input (device -> controller) IOCR.
std::unique_ptr< cyclic::CyclicController > controller