diff --git a/tests/components/daikin/daikin_regression_tests.cpp b/tests/components/daikin/daikin_regression_tests.cpp index fc642a84e9d..6bb41d30f49 100644 --- a/tests/components/daikin/daikin_regression_tests.cpp +++ b/tests/components/daikin/daikin_regression_tests.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "esphome/components/daikin/daikin.h" @@ -124,8 +123,6 @@ struct Rig { // A second fixture in the same test would otherwise restore what the first saved if (global_preferences != nullptr) global_preferences->reset(); - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; static char name[] = "test_daikin_regression"; static char friendly_name[] = ""; App.pre_setup(name, sizeof(name) - 1, friendly_name, 0); diff --git a/tests/components/daikin/daikin_tests.cpp b/tests/components/daikin/daikin_tests.cpp index 0664a82571c..3cea96cce4b 100644 --- a/tests/components/daikin/daikin_tests.cpp +++ b/tests/components/daikin/daikin_tests.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include @@ -146,9 +145,6 @@ struct Fixture { // A second fixture in the same test would otherwise restore what the first saved if (!keep_preferences && global_preferences != nullptr) global_preferences->reset(); - // The test main does not construct App as generated code does; the boost timer needs its scheduler - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; static char name[] = "test_daikin"; static char friendly_name[] = ""; App.pre_setup(name, sizeof(name) - 1, friendly_name, 0); diff --git a/tests/components/display/test_test_card.cpp b/tests/components/display/test_test_card.cpp index 555611bc093..a97301ac1e9 100644 --- a/tests/components/display/test_test_card.cpp +++ b/tests/components/display/test_test_card.cpp @@ -31,11 +31,6 @@ class TestCardDisplay : public Display { namespace { class TestCard : public ::testing::Test { protected: - void SetUp() override { - // test_card() stops the poller, which needs the scheduler; the test main does not construct App. - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; - } int writer_calls_{0}; display_writer_t count_writer_() { return [this](Display &) { this->writer_calls_++; }; diff --git a/tests/components/emontx/common.h b/tests/components/emontx/common.h index 678d582f62f..932fac91cd2 100644 --- a/tests/components/emontx/common.h +++ b/tests/components/emontx/common.h @@ -44,12 +44,6 @@ class MockUARTComponent : public uart::UARTComponent { #endif // defined(USE_ESP8266) || defined(USE_ESP32) }; -// The test main does not construct App as generated code does -inline void construct_app() { - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; -} - inline void cancel_timers(EmonTx *emontx) { for (uint32_t id = 0; id < 3; id++) App.scheduler.cancel_timeout(emontx, id); diff --git a/tests/components/emontx/emontx_test.cpp b/tests/components/emontx/emontx_test.cpp index 71bb6c70d36..227fa91a599 100644 --- a/tests/components/emontx/emontx_test.cpp +++ b/tests/components/emontx/emontx_test.cpp @@ -14,7 +14,6 @@ namespace { class EmonTxTest : public ::testing::Test { protected: void SetUp() override { - construct_app(); this->sut_.set_uart_parent(&this->uart_); this->sut_.add_on_data_callback([this](StringRef line) { this->lines_.emplace_back(line.c_str(), line.size()); }); this->sut_.add_on_json_callback([this](JsonObject, StringRef) { this->json_count_++; }); diff --git a/tests/components/emontx/text_sensor/emontx_version_test.cpp b/tests/components/emontx/text_sensor/emontx_version_test.cpp index 34f6315f3ab..fa51db63e5f 100644 --- a/tests/components/emontx/text_sensor/emontx_version_test.cpp +++ b/tests/components/emontx/text_sensor/emontx_version_test.cpp @@ -12,7 +12,6 @@ namespace { class EmonTxVersionTest : public ::testing::Test { protected: void SetUp() override { - construct_app(); this->sut_.set_uart_parent(&this->uart_); this->sut_.set_version_text_sensor(&this->version_); } diff --git a/tests/components/filter_lifetime/test_filter_lifetime.cpp b/tests/components/filter_lifetime/test_filter_lifetime.cpp index a4c89edd856..4f33afa24ef 100644 --- a/tests/components/filter_lifetime/test_filter_lifetime.cpp +++ b/tests/components/filter_lifetime/test_filter_lifetime.cpp @@ -39,7 +39,9 @@ class FilterLifetimeTest : public ::testing::Test { unsigned publications_{0}; void SetUp() override { - new (&App) Application; + // The test main keeps App alive; this test replaces it with a fresh one it owns + App.~Application(); + new (&App) Application(); App.pre_setup("filter-lifetime-tests", 21, "Filter lifetime tests", 21); host::setup_preferences(); host::host_preferences->reset(); @@ -55,6 +57,7 @@ class FilterLifetimeTest : public ::testing::Test { void TearDown() override { host::host_preferences->reset(); App.~Application(); + new (&App) Application(); // later tests and the test listener use App } void attach(FilterLifetime &filter) { diff --git a/tests/components/haier_water_heater/water_heater/test_hon_controller.cpp b/tests/components/haier_water_heater/water_heater/test_hon_controller.cpp index 41b40687d48..0de87d7a7da 100644 --- a/tests/components/haier_water_heater/water_heater/test_hon_controller.cpp +++ b/tests/components/haier_water_heater/water_heater/test_hon_controller.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "esphome/components/haier_water_heater/hon_water_heater.h" @@ -53,9 +52,6 @@ class TestableHeater : public HonWaterHeater { class HonControllerTest : public ::testing::Test { protected: void SetUp() override { - // The test runner skips generated setup(), which normally constructs App and its scheduler. - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; this->heater_.set_uart_parent(&this->uart_); this->heater_.set_network_pending(false); this->set_clock_(100); diff --git a/tests/components/i2c/test_i2c_chip_id.cpp b/tests/components/i2c/test_i2c_chip_id.cpp index c3e3fdd4907..a3b567d917d 100644 --- a/tests/components/i2c/test_i2c_chip_id.cpp +++ b/tests/components/i2c/test_i2c_chip_id.cpp @@ -33,7 +33,9 @@ class ChipDevice : public Component, public I2CDevice {}; class I2CChipIdTest : public ::testing::Test { protected: void SetUp() override { - new (&App) Application; + // The test main keeps App alive; this test replaces it with a fresh one it owns + App.~Application(); + new (&App) Application(); static char name[] = "i2c-chip-id-tests"; static char friendly_name[] = "I2C chip ID tests"; App.pre_setup(name, sizeof(name) - 1, friendly_name, sizeof(friendly_name) - 1); diff --git a/tests/components/main.cpp b/tests/components/main.cpp index 4020dd9a505..cbf19f31ba4 100644 --- a/tests/components/main.cpp +++ b/tests/components/main.cpp @@ -32,6 +32,11 @@ class ResetAppListener : public ::testing::EmptyTestEventListener { }; void setup() { + // Construct App once, as generated code does, before the logger, the listener or any test touches it. + // A fixture that destroys App must construct it again before returning. + // Placement new needs , which the generated include block already provides + new (&esphome::App) esphome::Application; + // Log functions call global_logger->log_vprintf_() without a null check, // so we must set up a Logger before any test that triggers logging. static esphome::logger::Logger test_logger(0); diff --git a/tests/components/mistral_ir/mistral_ir_tests.cpp b/tests/components/mistral_ir/mistral_ir_tests.cpp index 9b489154d02..b7260f95d88 100644 --- a/tests/components/mistral_ir/mistral_ir_tests.cpp +++ b/tests/components/mistral_ir/mistral_ir_tests.cpp @@ -84,9 +84,6 @@ struct Fixture { // A second fixture in the same test would otherwise restore what the first saved if (global_preferences != nullptr) global_preferences->reset(); - // The test main does not construct App as generated code does - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; static char name[] = "test_mistral_ir"; static char friendly_name[] = ""; App.pre_setup(name, sizeof(name) - 1, friendly_name, 0); diff --git a/tests/components/pd_pioneer_ir/pd_pioneer_ir_tests.cpp b/tests/components/pd_pioneer_ir/pd_pioneer_ir_tests.cpp index 293c363d5d6..76ffd5a70d4 100644 --- a/tests/components/pd_pioneer_ir/pd_pioneer_ir_tests.cpp +++ b/tests/components/pd_pioneer_ir/pd_pioneer_ir_tests.cpp @@ -72,9 +72,6 @@ struct Fixture { // A second fixture in the same test would otherwise restore what the first saved if (global_preferences != nullptr) global_preferences->reset(); - // The test main does not construct App as generated code does - static const bool APP_CONSTRUCTED = (new (&App) Application(), true); - (void) APP_CONSTRUCTED; static char name[] = "test_pd_pioneer_ir"; static char friendly_name[] = ""; App.pre_setup(name, sizeof(name) - 1, friendly_name, 0); diff --git a/tests/components/snapshot/snapshot_test.cpp b/tests/components/snapshot/snapshot_test.cpp index d63101357a2..92200814181 100644 --- a/tests/components/snapshot/snapshot_test.cpp +++ b/tests/components/snapshot/snapshot_test.cpp @@ -46,9 +46,6 @@ class SnapshotAnimationTest : public ::testing::Test { fs::remove_all(this->dir_); fs::create_directories(this->dir_); setenv("ESPHOME_SNAPSHOT_DIR", this->dir_.c_str(), 1); - // The test main does not construct App as generated code does, and recording needs its scheduler. - static const bool app_constructed = (new (&App) Application(), true); - (void) app_constructed; App.pre_setup("test_snapshot", 10, "", 0); } void TearDown() override { diff --git a/tests/components/tmp102/test_tmp102.cpp b/tests/components/tmp102/test_tmp102.cpp index a5b65b060d4..081dfba8d2c 100644 --- a/tests/components/tmp102/test_tmp102.cpp +++ b/tests/components/tmp102/test_tmp102.cpp @@ -71,7 +71,9 @@ class TMP102Test : public ::testing::Test { unsigned publications_{0}; void SetUp() override { - new (&App) Application; + // The test main keeps App alive; this test replaces it with a fresh one it owns + App.~Application(); + new (&App) Application(); App.pre_setup("tmp102-regression-tests", 23, "TMP102 tests", 12); host::setup_preferences(); host::host_preferences->reset(); @@ -93,6 +95,7 @@ class TMP102Test : public ::testing::Test { App.scheduler.call(millis()); host::host_preferences->reset(); App.~Application(); + new (&App) Application(); // later tests and the test listener use App } static void run_timers(uint32_t duration) { diff --git a/tests/components/xiaomi_body_scale/common.h b/tests/components/xiaomi_body_scale/common.h index 67f1eaae91a..e21b014efff 100644 --- a/tests/components/xiaomi_body_scale/common.h +++ b/tests/components/xiaomi_body_scale/common.h @@ -52,9 +52,6 @@ inline ble_device_base::ESPBTDevice advert(uint64_t address, const Frame &frame) struct Harness { Harness(uint64_t address, const char *key) : scale(address, key) { - // The test main does not construct App as generated code does; the stabilized reset needs its scheduler - static const bool app_constructed = (new (&App) Application(), true); - (void) app_constructed; App.pre_setup("test_scale", 10, "", 0); this->scale.set_weight(&this->weight); this->scale.set_impedance_low(&this->impedance_low);