diff --git a/firmware/controllers/algo/airmass/airmass.h b/firmware/controllers/algo/airmass/airmass.h index 338741da5f..b9c157a18a 100644 --- a/firmware/controllers/algo/airmass/airmass.h +++ b/firmware/controllers/algo/airmass/airmass.h @@ -2,6 +2,8 @@ #include "engine.h" +class ValueProvider3D; + struct AirmassResult { float CylinderAirmass = 0; float EngineLoadPercent = 100; diff --git a/firmware/controllers/algo/auto_generated_enums.cpp b/firmware/controllers/algo/auto_generated_enums.cpp index 3174670568..f7b61ecdb6 100644 --- a/firmware/controllers/algo/auto_generated_enums.cpp +++ b/firmware/controllers/algo/auto_generated_enums.cpp @@ -735,6 +735,8 @@ case LM_SPEED_DENSITY: return "LM_SPEED_DENSITY"; case LM_ALPHA_N_2: return "LM_ALPHA_N_2"; +case LM_MOCK: + return "LM_MOCK"; } return NULL; } diff --git a/firmware/controllers/algo/engine.h b/firmware/controllers/algo/engine.h index 6ec879af4e..a98c07c254 100644 --- a/firmware/controllers/algo/engine.h +++ b/firmware/controllers/algo/engine.h @@ -31,6 +31,7 @@ #define FAST_CALLBACK_PERIOD_MS 5 class RpmCalculator; +class AirmassModelBase; #define MAF_DECODING_CACHE_SIZE 256 @@ -334,6 +335,8 @@ public: void knockLogic(float knockVolts DECLARE_ENGINE_PARAMETER_SUFFIX); void printKnockState(void); + AirmassModelBase* mockAirmassModel = nullptr; + private: /** * By the way: diff --git a/firmware/controllers/algo/fuel_math.cpp b/firmware/controllers/algo/fuel_math.cpp index 7de041a545..7d60e77ea0 100644 --- a/firmware/controllers/algo/fuel_math.cpp +++ b/firmware/controllers/algo/fuel_math.cpp @@ -179,6 +179,9 @@ AirmassModelBase* getAirmassModel(DECLARE_ENGINE_PARAMETER_SIGNATURE) { case LM_SPEED_DENSITY: return &sdAirmass; case LM_REAL_MAF: return &mafAirmass; case LM_ALPHA_N_2: return &alphaNAirmass; +#if EFI_UNIT_TEST + case LM_MOCK: return engine->mockAirmassModel; +#endif default: return nullptr; } } @@ -198,7 +201,8 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) { if ((CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) || (engineConfiguration->fuelAlgorithm == LM_REAL_MAF) || - (engineConfiguration->fuelAlgorithm == LM_ALPHA_N_2)) { + (engineConfiguration->fuelAlgorithm == LM_ALPHA_N_2) || + (engineConfiguration->fuelAlgorithm == LM_MOCK)) { // airmass modes - get airmass first, then convert to fuel auto model = getAirmassModel(PASS_ENGINE_PARAMETER_SIGNATURE); efiAssert(CUSTOM_ERR_ASSERT, model != nullptr, "Invalid airmass mode", 0.0f); diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 9736c26d92..915318e7b4 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -446,6 +446,9 @@ typedef enum { // todo: rename after LM_ALPHA_N is removed LM_ALPHA_N_2 = 5, + // This mode is for unit testing only, so that tests don't have to rely on a particular real airmass mode + LM_MOCK = 100, + Force_4_bytes_size_engine_load_mode = ENUM_32_BITS, } engine_load_mode_e; diff --git a/unit_tests/engine_test_helper.cpp b/unit_tests/engine_test_helper.cpp index a62a9ce011..e0ef38c70b 100644 --- a/unit_tests/engine_test_helper.cpp +++ b/unit_tests/engine_test_helper.cpp @@ -83,6 +83,10 @@ EngineTestHelper::EngineTestHelper(engine_type_e engineType, configuration_callb // this is needed to have valid CLT and IAT. //todo: reuse initPeriodicEvents(PASS_ENGINE_PARAMETER_SIGNATURE) method engine->periodicSlowCallback(PASS_ENGINE_PARAMETER_SIGNATURE); + + // Setup running in mock airmass mode + engineConfiguration->fuelAlgorithm = LM_MOCK; + engine->mockAirmassModel = &mockAirmass; } EngineTestHelper::~EngineTestHelper() { @@ -315,7 +319,6 @@ void setupSimpleTestEngineWithMaf(EngineTestHelper *eth, injection_mode_e inject eth->clearQueue(); - ASSERT_EQ(LM_PLAIN_MAF, engineConfiguration->fuelAlgorithm); engineConfiguration->isIgnitionEnabled = false; // let's focus on injection engineConfiguration->specs.cylindersCount = 4; // a bit of flexibility - the mode may be changed by some tests diff --git a/unit_tests/engine_test_helper.h b/unit_tests/engine_test_helper.h index 9431eb10ac..8f92b36d4f 100644 --- a/unit_tests/engine_test_helper.h +++ b/unit_tests/engine_test_helper.h @@ -13,6 +13,7 @@ #include "main_trigger_callback.h" #include "unit_test_framework.h" #include "sensor.h" +#include "mocks.h" extern EnginePins enginePins; @@ -83,6 +84,8 @@ public: Engine engine; persistent_config_s persistentConfig; + ::testing::NiceMock mockAirmass; + private: void writeEvents(const char *fileName); }; diff --git a/unit_tests/mocks.h b/unit_tests/mocks.h index dcaad8ebb4..fb60970c94 100644 --- a/unit_tests/mocks.h +++ b/unit_tests/mocks.h @@ -1,7 +1,10 @@ +#pragma once + #include "electronic_throttle.h" #include "dc_motor.h" #include "table_helper.h" #include "pwm_generator_logic.h" +#include "airmass.h" #include "gmock/gmock.h" @@ -52,3 +55,12 @@ public: MOCK_METHOD(void, scheduleByTimestampNt, (scheduling_s *scheduling, efitime_t timeUs, action_s action), (override)); MOCK_METHOD(void, scheduleForLater, (scheduling_s *scheduling, int delayUs, action_s action), (override)); }; + +class MockAirmass : public AirmassModelBase { +public: + MockAirmass() : AirmassModelBase(veTable) {} + + MockVp3d veTable; + + MOCK_METHOD(AirmassResult, getAirmass, (int rpm), (override)); +}; diff --git a/unit_tests/tests/ignition_injection/injection_mode_transition.cpp b/unit_tests/tests/ignition_injection/injection_mode_transition.cpp index e2ece5d105..6f4639963b 100644 --- a/unit_tests/tests/ignition_injection/injection_mode_transition.cpp +++ b/unit_tests/tests/ignition_injection/injection_mode_transition.cpp @@ -31,6 +31,9 @@ TEST(fuelControl, transitionIssue1592) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð, IM_SEQUENTIAL); + EXPECT_CALL(eth.mockAirmass, getAirmass(400)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); + // This is easiest to trip on a wheel that requires sync engineConfiguration->trigger.customTotalToothCount = 6; engineConfiguration->trigger.customSkippedToothCount = 1; @@ -38,10 +41,6 @@ TEST(fuelControl, transitionIssue1592) { engineConfiguration->ambiguousOperationMode = FOUR_STROKE_CAM_SENSOR; engineConfiguration->isFasterEngineSpinUpEnabled = true; - engineConfiguration->fuelAlgorithm = LM_ALPHA_N; - - extern fuel_Map3D_t fuelMap; - fuelMap.setAll(13); extern fuel_Map3D_t fuelPhaseMap; fuelPhaseMap.setAll(0); setArrayValues(config->crankingFuelCoef, 1.0f); diff --git a/unit_tests/tests/ignition_injection/test_fuelCut.cpp b/unit_tests/tests/ignition_injection/test_fuelCut.cpp index 21c7f6f540..47396bcdd7 100644 --- a/unit_tests/tests/ignition_injection/test_fuelCut.cpp +++ b/unit_tests/tests/ignition_injection/test_fuelCut.cpp @@ -11,8 +11,12 @@ #include "sensor.h" #include "fsio_impl.h" +using ::testing::_; + TEST(fuelCut, coasting) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); // configure coastingFuelCut engineConfiguration->coastingFuelCutEnabled = true; diff --git a/unit_tests/tests/test_fuel_map.cpp b/unit_tests/tests/test_fuel_map.cpp index 1736cc7c89..14dbbcb386 100644 --- a/unit_tests/tests/test_fuel_map.cpp +++ b/unit_tests/tests/test_fuel_map.cpp @@ -21,6 +21,7 @@ using ::testing::FloatNear; TEST(misc, testFuelMap) { printf("Setting up FORD_ASPIRE_1996\r\n"); WITH_ENGINE_TEST_HELPER(FORD_ASPIRE_1996); + engineConfiguration->fuelAlgorithm = LM_PLAIN_MAF; printf("Filling fuel map\r\n"); for (int k = 0; k < FUEL_LOAD_COUNT; k++) { diff --git a/unit_tests/tests/trigger/test_trigger_decoder.cpp b/unit_tests/tests/trigger/test_trigger_decoder.cpp index 58d33dcfe5..5aa73cccec 100644 --- a/unit_tests/tests/trigger/test_trigger_decoder.cpp +++ b/unit_tests/tests/trigger/test_trigger_decoder.cpp @@ -23,6 +23,8 @@ #include "trigger_universal.h" #include "sensor.h" +using ::testing::_; + extern WarningCodeState unitTestWarningCodeState; extern bool printTriggerDebug; extern float actualSynchGap; @@ -295,9 +297,10 @@ static void assertREqualsM(const char *msg, void *expected, void *actual) { extern bool_t debugSignalExecutor; TEST(misc, testRpmCalculator) { - printf("*************************************************** testRpmCalculator\r\n"); - WITH_ENGINE_TEST_HELPER(FORD_INLINE_6_1995); + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); + IgnitionEventList *ilist = &engine->ignitionEvents; ASSERT_EQ( 0, ilist->isReady) << "size #1"; @@ -588,6 +591,8 @@ static void assertInjectionEventBatch(const char *msg, InjectionEvent *ev, int i } static void setTestBug299(EngineTestHelper *eth) { + // TODO: switch to mock airmass + eth->persistentConfig.engineConfiguration.fuelAlgorithm = LM_PLAIN_MAF; setupSimpleTestEngineWithMafAndTT_ONE_trigger(eth); Engine *engine = ð->engine; EXPAND_Engine @@ -977,6 +982,8 @@ TEST(big, testFuelSchedulerBug299smallAndMedium) { TEST(big, testTwoWireBatch) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð); + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); engineConfiguration->injectionMode = IM_BATCH; engineConfiguration->twoWireBatchInjection = true; @@ -1002,6 +1009,9 @@ TEST(big, testTwoWireBatch) { TEST(big, testSequential) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); + setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð); engineConfiguration->injectionMode = IM_SEQUENTIAL;