Files
2026-06-12 15:25:13 +02:00

223 lines
7.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file TriggerEngineGTest.cpp
* @brief Unit tests for the StreamHub hub-side trigger FSM.
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*/
#include "TriggerEngine.h"
#include <gtest/gtest.h>
using namespace StreamHub;
using MARTe::float64;
static TriggerConfig MakeConfig(TrigEdge edge, float64 threshold,
float64 windowSec, float64 prePercent,
TrigAcqMode mode = kTrigNormal) {
TriggerConfig cfg;
cfg.signalKey = "src:sig";
cfg.edge = edge;
cfg.threshold = threshold;
cfg.windowSec = windowSec;
cfg.prePercent = prePercent;
cfg.mode = mode;
return cfg;
}
TEST(TriggerEngineGTest, TestInitialState) {
TriggerEngine eng;
EXPECT_EQ(kTrigIdle, eng.GetState());
EXPECT_FALSE(eng.GetStopped());
float64 tt, pre, post;
EXPECT_FALSE(eng.GetFiredWindow(tt, pre, post));
}
TEST(TriggerEngineGTest, TestIdleIgnoresSamples) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0); /* would fire if armed */
EXPECT_EQ(kTrigIdle, eng.GetState());
}
TEST(TriggerEngineGTest, TestRisingEdgeFires) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.Arm();
EXPECT_EQ(kTrigArmed, eng.GetState());
eng.CheckSample(1.0, 0.0); /* primes prevValue */
eng.CheckSample(2.0, 1.0); /* 0.0 < 0.5 <= 1.0 → fire */
EXPECT_EQ(kTrigCollecting, eng.GetState());
float64 tt, pre, post;
ASSERT_TRUE(eng.GetFiredWindow(tt, pre, post));
EXPECT_DOUBLE_EQ(2.0, tt);
EXPECT_DOUBLE_EQ(0.2, pre); /* 1.0 s × 20 % */
EXPECT_DOUBLE_EQ(0.8, post);
}
TEST(TriggerEngineGTest, TestFirstSampleNeverFires) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.Arm();
/* First sample above threshold must only prime the detector */
eng.CheckSample(1.0, 2.0);
EXPECT_EQ(kTrigArmed, eng.GetState());
}
TEST(TriggerEngineGTest, TestFallingEdgeFires) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeFalling, 0.5, 1.0, 50.0));
eng.Arm();
eng.CheckSample(1.0, 1.0);
eng.CheckSample(2.0, 1.5); /* rising: must not fire */
EXPECT_EQ(kTrigArmed, eng.GetState());
eng.CheckSample(3.0, 0.2); /* 1.5 > 0.5 >= 0.2 → fire */
EXPECT_EQ(kTrigCollecting, eng.GetState());
float64 tt, pre, post;
ASSERT_TRUE(eng.GetFiredWindow(tt, pre, post));
EXPECT_DOUBLE_EQ(3.0, tt);
EXPECT_DOUBLE_EQ(0.5, pre);
EXPECT_DOUBLE_EQ(0.5, post);
}
TEST(TriggerEngineGTest, TestBothEdgesFire) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeBoth, 0.0, 1.0, 0.0));
eng.Arm();
eng.CheckSample(1.0, -1.0);
eng.CheckSample(2.0, 1.0); /* rising through 0 */
EXPECT_EQ(kTrigCollecting, eng.GetState());
eng.Arm();
eng.CheckSample(3.0, 1.0);
eng.CheckSample(4.0, -1.0); /* falling through 0 */
EXPECT_EQ(kTrigCollecting, eng.GetState());
}
TEST(TriggerEngineGTest, TestNoFireBelowThreshold) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 5.0, 1.0, 20.0));
eng.Arm();
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0);
eng.CheckSample(3.0, 4.9);
EXPECT_EQ(kTrigArmed, eng.GetState());
}
TEST(TriggerEngineGTest, TestConfigClamping) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.0, 100.0, 150.0));
TriggerConfig cfg = eng.GetConfig();
EXPECT_DOUBLE_EQ(10.0, cfg.windowSec);
EXPECT_DOUBLE_EQ(100.0, cfg.prePercent);
eng.SetConfig(MakeConfig(kEdgeRising, 0.0, 1.0e-6, -5.0));
cfg = eng.GetConfig();
EXPECT_DOUBLE_EQ(1.0e-4, cfg.windowSec);
EXPECT_DOUBLE_EQ(0.0, cfg.prePercent);
}
TEST(TriggerEngineGTest, TestConfigEpochIncrements) {
TriggerEngine eng;
MARTe::uint32 e0 = eng.GetConfigEpoch();
eng.SetConfig(MakeConfig(kEdgeRising, 0.0, 1.0, 20.0));
EXPECT_EQ(e0 + 1u, eng.GetConfigEpoch());
eng.SetConfig(MakeConfig(kEdgeFalling, 1.0, 2.0, 30.0));
EXPECT_EQ(e0 + 2u, eng.GetConfigEpoch());
}
TEST(TriggerEngineGTest, TestMarkTriggeredOnlyFromCollecting) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
/* Not collecting: no-op */
eng.MarkTriggered();
EXPECT_EQ(kTrigIdle, eng.GetState());
eng.Arm();
eng.MarkTriggered();
EXPECT_EQ(kTrigArmed, eng.GetState());
/* Collecting → triggered */
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0);
ASSERT_EQ(kTrigCollecting, eng.GetState());
eng.MarkTriggered();
EXPECT_EQ(kTrigTriggered, eng.GetState());
}
TEST(TriggerEngineGTest, TestDisarmResetsEverything) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.Arm();
eng.SetStopped(true);
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0);
ASSERT_EQ(kTrigCollecting, eng.GetState());
eng.Disarm();
EXPECT_EQ(kTrigIdle, eng.GetState());
EXPECT_FALSE(eng.GetStopped());
float64 tt, pre, post;
EXPECT_FALSE(eng.GetFiredWindow(tt, pre, post));
}
TEST(TriggerEngineGTest, TestRearmResetsEdgeDetection) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.Arm();
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0);
eng.MarkTriggered();
ASSERT_EQ(kTrigTriggered, eng.GetState());
/* Re-arm: first sample only primes even if it crosses the threshold
* relative to the value seen before the re-arm. */
eng.Arm();
EXPECT_EQ(kTrigArmed, eng.GetState());
eng.CheckSample(3.0, 0.0);
EXPECT_EQ(kTrigArmed, eng.GetState());
eng.CheckSample(4.0, 1.0);
EXPECT_EQ(kTrigCollecting, eng.GetState());
float64 tt, pre, post;
ASSERT_TRUE(eng.GetFiredWindow(tt, pre, post));
EXPECT_DOUBLE_EQ(4.0, tt);
}
TEST(TriggerEngineGTest, TestStoppedFlag) {
TriggerEngine eng;
EXPECT_FALSE(eng.GetStopped());
eng.SetStopped(true);
EXPECT_TRUE(eng.GetStopped());
eng.SetStopped(false);
EXPECT_FALSE(eng.GetStopped());
}
TEST(TriggerEngineGTest, TestWindowLatchedAtFireTime) {
TriggerEngine eng;
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 1.0, 20.0));
eng.Arm();
eng.CheckSample(1.0, 0.0);
eng.CheckSample(2.0, 1.0);
ASSERT_EQ(kTrigCollecting, eng.GetState());
/* Config edits after the fire must not change the latched window */
eng.SetConfig(MakeConfig(kEdgeRising, 0.5, 10.0, 50.0));
float64 tt, pre, post;
ASSERT_TRUE(eng.GetFiredWindow(tt, pre, post));
EXPECT_DOUBLE_EQ(0.2, pre);
EXPECT_DOUBLE_EQ(0.8, post);
}