From 2c32ac22212a8854d09672d4cb9606d71081832b Mon Sep 17 00:00:00 2001 From: Boris Krivonog Date: Sun, 23 Aug 2026 21:40:08 +0200 Subject: [PATCH] [mitsubishi_cn105] Mark configurable classes as final (#18272) --- .../components/mitsubishi_cn105/automation.h | 6 +- .../mitsubishi_cn105_climate.cpp | 83 ++------ .../mitsubishi_cn105_climate.h | 13 +- .../mitsubishi_cn105_component.h | 2 +- .../mitsubishi_cn105_swing_mode_manager.h | 86 +++++++++ .../mitsubishi_cn105_vane_select_vertical.h | 6 +- .../mitsubishi_cn105_climate_tests.cpp | 180 ++++-------------- ...subishi_cn105_swing_mode_manager_tests.cpp | 99 ++++++++++ tests/components/mitsubishi_cn105/common.h | 22 --- .../mitsubishi_cn105_component_tests.cpp | 21 +- ...bishi_cn105_vane_select_vertical_tests.cpp | 33 ++-- 11 files changed, 278 insertions(+), 273 deletions(-) create mode 100644 esphome/components/mitsubishi_cn105/mitsubishi_cn105_swing_mode_manager.h create mode 100644 tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_swing_mode_manager_tests.cpp diff --git a/esphome/components/mitsubishi_cn105/automation.h b/esphome/components/mitsubishi_cn105/automation.h index 2fc6ba3c32..f9ca3a47e6 100644 --- a/esphome/components/mitsubishi_cn105/automation.h +++ b/esphome/components/mitsubishi_cn105/automation.h @@ -9,7 +9,7 @@ namespace esphome::mitsubishi_cn105 { template -class SetRemoteTemperatureAction : public Action, public Parented { +class SetRemoteTemperatureAction final : public Action, public Parented { public: TEMPLATABLE_VALUE(float, temperature) @@ -17,12 +17,12 @@ class SetRemoteTemperatureAction : public Action, public Parented -class ClearRemoteTemperatureAction : public Action, public Parented { +class ClearRemoteTemperatureAction final : public Action, public Parented { public: void play(const Ts &...x) override { this->parent_->clear_remote_temperature(); } }; -template class VaneControlAction : public Action { +template class VaneControlAction final : public Action { public: using ApplyFn = void (*)(VaneCall &, const std::remove_cvref_t &...); diff --git a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.cpp b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.cpp index 17ff6d34ca..53b8c21de6 100644 --- a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.cpp +++ b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.cpp @@ -74,7 +74,7 @@ climate::ClimateTraits MitsubishiCN105Climate::traits() { traits.add_supported_fan_mode(p.second); } - traits.set_supported_swing_modes(this->supported_swing_modes_); + traits.set_supported_swing_modes(this->swing_mode_manager_.supported_swing_modes()); const bool use_fahrenheit = this->parent_->get_temperature_mapping().get_use_fahrenheit(); traits.set_temperature_unit(use_fahrenheit ? TemperatureUnit::FAHRENHEIT : TemperatureUnit::CELSIUS); @@ -109,33 +109,11 @@ void MitsubishiCN105Climate::control(const climate::ClimateCall &call) { } if (const auto swing_mode = call.get_swing_mode()) { - auto vane = this->last_non_swing_vane_mode_; - auto wide = this->last_non_swing_wide_vane_mode_; - - switch (*swing_mode) { - case climate::CLIMATE_SWING_BOTH: - vane = MitsubishiCN105::VaneMode::SWING; - wide = MitsubishiCN105::WideVaneMode::SWING; - break; - - case climate::CLIMATE_SWING_VERTICAL: - vane = MitsubishiCN105::VaneMode::SWING; - break; - - case climate::CLIMATE_SWING_HORIZONTAL: - wide = MitsubishiCN105::WideVaneMode::SWING; - break; - - case climate::CLIMATE_SWING_OFF: - default: - break; + if (const auto vane = this->swing_mode_manager_.vane_from(*swing_mode)) { + this->parent_->set_vane_mode(*vane); } - - if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_VERTICAL)) { - this->parent_->set_vane_mode(vane); - } - if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_HORIZONTAL)) { - this->parent_->set_wide_vane_mode(wide); + if (const auto wide = this->swing_mode_manager_.wide_vane_from(*swing_mode)) { + this->parent_->set_wide_vane_mode(*wide); } } @@ -166,64 +144,39 @@ void MitsubishiCN105Climate::apply_values_() { ESP_LOGD(TAG, "Unable to map fan mode"); } - if (!this->supported_swing_modes_.empty()) { - bool vertical_swinging = false; - bool horizontal_swinging = false; - - if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_VERTICAL)) { - if (status.vane_mode == MitsubishiCN105::VaneMode::SWING) { - vertical_swinging = true; - } else if (status.vane_mode != MitsubishiCN105::VaneMode::UNKNOWN) { - this->last_non_swing_vane_mode_ = status.vane_mode; - } - } - - if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_HORIZONTAL)) { - if (status.wide_vane_mode == MitsubishiCN105::WideVaneMode::SWING) { - horizontal_swinging = true; - } else if (status.wide_vane_mode != MitsubishiCN105::WideVaneMode::UNKNOWN) { - this->last_non_swing_wide_vane_mode_ = status.wide_vane_mode; - } - } - - if (vertical_swinging && horizontal_swinging) { - this->swing_mode = climate::CLIMATE_SWING_BOTH; - } else if (vertical_swinging) { - this->swing_mode = climate::CLIMATE_SWING_VERTICAL; - } else if (horizontal_swinging) { - this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; - } else { - this->swing_mode = climate::CLIMATE_SWING_OFF; - } + if (const auto swing_mode = + this->swing_mode_manager_.update_and_get_swing_mode(status.vane_mode, status.wide_vane_mode)) { + this->swing_mode = *swing_mode; } this->publish_state(); } void MitsubishiCN105Climate::set_supported_swing_mode(climate::ClimateSwingMode mode) { - this->supported_swing_modes_.clear(); + climate::ClimateSwingModeMask supported_swing_modes; switch (mode) { case climate::CLIMATE_SWING_VERTICAL: - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_OFF); - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_VERTICAL); + supported_swing_modes.insert(climate::CLIMATE_SWING_OFF); + supported_swing_modes.insert(climate::CLIMATE_SWING_VERTICAL); break; case climate::CLIMATE_SWING_HORIZONTAL: - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_OFF); - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_HORIZONTAL); + supported_swing_modes.insert(climate::CLIMATE_SWING_OFF); + supported_swing_modes.insert(climate::CLIMATE_SWING_HORIZONTAL); break; case climate::CLIMATE_SWING_BOTH: - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_OFF); - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_VERTICAL); - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_HORIZONTAL); - this->supported_swing_modes_.insert(climate::CLIMATE_SWING_BOTH); + supported_swing_modes.insert(climate::CLIMATE_SWING_OFF); + supported_swing_modes.insert(climate::CLIMATE_SWING_VERTICAL); + supported_swing_modes.insert(climate::CLIMATE_SWING_HORIZONTAL); + supported_swing_modes.insert(climate::CLIMATE_SWING_BOTH); break; case climate::CLIMATE_SWING_OFF: default: break; } + this->swing_mode_manager_.set_supported_swing_modes(supported_swing_modes); } } // namespace esphome::mitsubishi_cn105 diff --git a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.h b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.h index 5341c2d2d9..cea76278ab 100644 --- a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.h +++ b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.h @@ -6,10 +6,13 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/components/climate/climate.h" +#include "mitsubishi_cn105_swing_mode_manager.h" namespace esphome::mitsubishi_cn105 { -class MitsubishiCN105Climate : public climate::Climate, public Component, public Parented { +class MitsubishiCN105Climate final : public climate::Climate, + public Component, + public Parented { public: void setup() override; void dump_config() override; @@ -25,14 +28,12 @@ class MitsubishiCN105Climate : public climate::Climate, public Component, public protected: void apply_values_(); - climate::ClimateSwingModeMask supported_swing_modes_{}; - MitsubishiCN105::VaneMode last_non_swing_vane_mode_{MitsubishiCN105::VaneMode::AUTO}; - MitsubishiCN105::WideVaneMode last_non_swing_wide_vane_mode_{MitsubishiCN105::WideVaneMode::CENTER}; + SwingModeManager swing_mode_manager_; }; // Legacy climate action compatibility. Remove in 2027.2.0. template -class LegacySetRemoteTemperatureAction : public Action, public Parented { +class LegacySetRemoteTemperatureAction final : public Action, public Parented { public: TEMPLATABLE_VALUE(float, temperature) @@ -41,7 +42,7 @@ class LegacySetRemoteTemperatureAction : public Action, public Parented -class LegacyClearRemoteTemperatureAction : public Action, public Parented { +class LegacyClearRemoteTemperatureAction final : public Action, public Parented { public: void play(const Ts &...x) override { this->parent_->clear_remote_temperature(); } }; diff --git a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_component.h b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_component.h index 508a15e6d5..aa9bfe0d8c 100644 --- a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_component.h +++ b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_component.h @@ -80,7 +80,7 @@ struct VaneCall { MitsubishiCN105Component *parent_; }; -class MitsubishiCN105Component : public Component, public uart::UARTDevice { +class MitsubishiCN105Component final : public Component, public uart::UARTDevice { public: explicit MitsubishiCN105Component() : hp_(*this) {} diff --git a/esphome/components/mitsubishi_cn105/mitsubishi_cn105_swing_mode_manager.h b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_swing_mode_manager.h new file mode 100644 index 0000000000..20f54f0bbb --- /dev/null +++ b/esphome/components/mitsubishi_cn105/mitsubishi_cn105_swing_mode_manager.h @@ -0,0 +1,86 @@ +#pragma once + +#include + +#include "esphome/components/climate/climate.h" +#include "mitsubishi_cn105.h" + +namespace esphome::mitsubishi_cn105 { + +class SwingModeManager final { + public: + const climate::ClimateSwingModeMask &supported_swing_modes() const { return this->supported_swing_modes_; } + void set_supported_swing_modes(const climate::ClimateSwingModeMask &supported_swing_modes) { + this->supported_swing_modes_ = supported_swing_modes; + } + + std::optional vane_from(climate::ClimateSwingMode swing_mode) const { + if (!this->supported_swing_modes_.count(climate::CLIMATE_SWING_VERTICAL)) { + return std::nullopt; + } + + switch (swing_mode) { + case climate::CLIMATE_SWING_BOTH: + case climate::CLIMATE_SWING_VERTICAL: + return MitsubishiCN105::VaneMode::SWING; + default: + return this->last_non_swing_vane_mode_; + } + } + + std::optional wide_vane_from(climate::ClimateSwingMode swing_mode) const { + if (!this->supported_swing_modes_.count(climate::CLIMATE_SWING_HORIZONTAL)) { + return std::nullopt; + } + + switch (swing_mode) { + case climate::CLIMATE_SWING_BOTH: + case climate::CLIMATE_SWING_HORIZONTAL: + return MitsubishiCN105::WideVaneMode::SWING; + default: + return this->last_non_swing_wide_vane_mode_; + } + } + + std::optional update_and_get_swing_mode(MitsubishiCN105::VaneMode vane_mode, + MitsubishiCN105::WideVaneMode wide_vane_mode) { + if (this->supported_swing_modes_.empty()) { + return std::nullopt; + } + + bool vertical_swinging = false; + bool horizontal_swinging = false; + if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_VERTICAL)) { + if (vane_mode == MitsubishiCN105::VaneMode::SWING) { + vertical_swinging = true; + } else if (vane_mode != MitsubishiCN105::VaneMode::UNKNOWN) { + this->last_non_swing_vane_mode_ = vane_mode; + } + } + if (this->supported_swing_modes_.count(climate::CLIMATE_SWING_HORIZONTAL)) { + if (wide_vane_mode == MitsubishiCN105::WideVaneMode::SWING) { + horizontal_swinging = true; + } else if (wide_vane_mode != MitsubishiCN105::WideVaneMode::UNKNOWN) { + this->last_non_swing_wide_vane_mode_ = wide_vane_mode; + } + } + + if (vertical_swinging && horizontal_swinging) { + return climate::CLIMATE_SWING_BOTH; + } + if (vertical_swinging) { + return climate::CLIMATE_SWING_VERTICAL; + } + if (horizontal_swinging) { + return climate::CLIMATE_SWING_HORIZONTAL; + } + return climate::CLIMATE_SWING_OFF; + } + + private: + climate::ClimateSwingModeMask supported_swing_modes_{}; + MitsubishiCN105::VaneMode last_non_swing_vane_mode_{MitsubishiCN105::VaneMode::AUTO}; + MitsubishiCN105::WideVaneMode last_non_swing_wide_vane_mode_{MitsubishiCN105::WideVaneMode::CENTER}; +}; + +} // namespace esphome::mitsubishi_cn105 diff --git a/esphome/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical.h b/esphome/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical.h index 76977d59d7..656b78b487 100644 --- a/esphome/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical.h +++ b/esphome/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical.h @@ -7,9 +7,9 @@ namespace esphome::mitsubishi_cn105 { -class MitsubishiCN105VerticalVaneDirectionSelect : public select::Select, - public Component, - public Parented { +class MitsubishiCN105VerticalVaneDirectionSelect final : public select::Select, + public Component, + public Parented { public: void setup() override; void publish_vane_state(MitsubishiCN105::VaneMode mode); diff --git a/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_climate_tests.cpp b/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_climate_tests.cpp index b91252c9fa..669345f576 100644 --- a/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_climate_tests.cpp +++ b/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_climate_tests.cpp @@ -2,10 +2,19 @@ #include #include "../common.h" +#include "esphome/components/mitsubishi_cn105/mitsubishi_cn105_climate.h" + namespace esphome::mitsubishi_cn105::testing { +struct MitsubishiCN105ClimateTestContext { + MitsubishiCN105Component component; + MitsubishiCN105Climate sut; + + MitsubishiCN105ClimateTestContext() { this->sut.set_parent(&this->component); } +}; + TEST(MitsubishiCN105ClimateTests, CelsiusTemperatureMappingAndTraitsMatchExpectedValues) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; const auto mapping = TemperatureMapping(); for (int temperature = 16; temperature <= 31; ++temperature) { @@ -13,7 +22,7 @@ TEST(MitsubishiCN105ClimateTests, CelsiusTemperatureMappingAndTraitsMatchExpecte EXPECT_EQ(mapping.from_mitsubishi(temperature), temperature); } - const auto traits = sut.traits(); + const auto traits = context.sut.traits(); EXPECT_EQ(traits.get_temperature_unit(), TemperatureUnit::CELSIUS); EXPECT_FLOAT_EQ(traits.get_visual_min_temperature(), 16.0f); EXPECT_FLOAT_EQ(traits.get_visual_max_temperature(), 31.0f); @@ -22,10 +31,10 @@ TEST(MitsubishiCN105ClimateTests, CelsiusTemperatureMappingAndTraitsMatchExpecte } TEST(MitsubishiCN105ClimateTests, FahrenheitTemperatureMappingAndTraitsMatchExpectedValues) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; auto mapping = TemperatureMapping(); mapping.set_use_fahrenheit(true); - sut.set_use_fahrenheit(true); + context.component.set_use_fahrenheit(true); const std::array cases{ std::pair{61, 16.0f}, std::pair{62, 16.5f}, std::pair{63, 17.0f}, std::pair{64, 17.5f}, std::pair{65, 18.0f}, @@ -40,7 +49,7 @@ TEST(MitsubishiCN105ClimateTests, FahrenheitTemperatureMappingAndTraitsMatchExpe EXPECT_FLOAT_EQ(mapping.to_mitsubishi(fahrenheit), mitsubishi_celsius); EXPECT_FLOAT_EQ(mapping.from_mitsubishi(mitsubishi_celsius), fahrenheit); } - const auto traits = sut.traits(); + const auto traits = context.sut.traits(); EXPECT_EQ(traits.get_temperature_unit(), TemperatureUnit::FAHRENHEIT); EXPECT_FLOAT_EQ(traits.get_visual_min_temperature(), 61.0f); EXPECT_FLOAT_EQ(traits.get_visual_max_temperature(), 88.0f); @@ -63,163 +72,44 @@ TEST(MitsubishiCN105ClimateTests, FahrenheitTemperatureMappingUsesLinearConversi } TEST(MitsubishiCN105ClimateTests, SupportedSwingModeOffLeavesTraitsEmpty) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; - sut.set_supported_swing_mode(climate::CLIMATE_SWING_OFF); + context.sut.set_supported_swing_mode(climate::CLIMATE_SWING_OFF); - EXPECT_FALSE(sut.traits().get_supports_swing_modes()); + EXPECT_FALSE(context.sut.traits().get_supports_swing_modes()); } TEST(MitsubishiCN105ClimateTests, SupportedSwingModeVerticalExposesOffAndVertical) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; - sut.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); + context.sut.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); - EXPECT_FALSE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); - EXPECT_FALSE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); + EXPECT_FALSE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); + EXPECT_FALSE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); } TEST(MitsubishiCN105ClimateTests, SupportedSwingModeHorizontalExposesOffAndHorizontal) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; - sut.set_supported_swing_mode(climate::CLIMATE_SWING_HORIZONTAL); + context.sut.set_supported_swing_mode(climate::CLIMATE_SWING_HORIZONTAL); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); - EXPECT_FALSE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); - EXPECT_FALSE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); + EXPECT_FALSE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); + EXPECT_FALSE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); } TEST(MitsubishiCN105ClimateTests, SupportedSwingModeBothExposesAllExpectedModes) { - TestableMitsubishiCN105Climate sut; + MitsubishiCN105ClimateTestContext context; - sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); + context.sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); - EXPECT_TRUE(sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesMapsVerticalSwingWhenSupported) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::SWING; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::CENTER; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_VERTICAL); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesMapsHorizontalSwingWhenSupported) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_HORIZONTAL); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::AUTO; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::SWING; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_HORIZONTAL); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesMapsBothSwingWhenSupported) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::SWING; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::SWING; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_BOTH); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesMapsSwingOffWhenNoSwingActive) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::POSITION_3; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::CENTER; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_OFF); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesRemembersLastNonSwingPositions) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::POSITION_4; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::RIGHT; - - sut.apply_values_(); - - EXPECT_EQ(sut.last_non_swing_vane_mode_, MitsubishiCN105::VaneMode::POSITION_4); - EXPECT_EQ(sut.last_non_swing_wide_vane_mode_, MitsubishiCN105::WideVaneMode::RIGHT); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::SWING; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::SWING; - - sut.apply_values_(); - - EXPECT_EQ(sut.last_non_swing_vane_mode_, MitsubishiCN105::VaneMode::POSITION_4); - EXPECT_EQ(sut.last_non_swing_wide_vane_mode_, MitsubishiCN105::WideVaneMode::RIGHT); - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_BOTH); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesDoesNotOverwriteRememberedPositionWithUnknownValues) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_BOTH); - - sut.last_non_swing_vane_mode_ = MitsubishiCN105::VaneMode::POSITION_2; - sut.last_non_swing_wide_vane_mode_ = MitsubishiCN105::WideVaneMode::LEFT; - - sut.status().vane_mode = MitsubishiCN105::VaneMode::UNKNOWN; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::UNKNOWN; - - sut.apply_values_(); - - EXPECT_EQ(sut.last_non_swing_vane_mode_, MitsubishiCN105::VaneMode::POSITION_2); - EXPECT_EQ(sut.last_non_swing_wide_vane_mode_, MitsubishiCN105::WideVaneMode::LEFT); - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_OFF); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesIgnoresUnsupportedVerticalSwingState) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_HORIZONTAL); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::SWING; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::CENTER; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_OFF); -} - -TEST(MitsubishiCN105ClimateTests, ApplyValuesIgnoresUnsupportedHorizontalSwingState) { - TestableMitsubishiCN105Climate sut; - - sut.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); - - sut.status().vane_mode = MitsubishiCN105::VaneMode::AUTO; - sut.status().wide_vane_mode = MitsubishiCN105::WideVaneMode::SWING; - - sut.apply_values_(); - - EXPECT_EQ(sut.swing_mode, climate::CLIMATE_SWING_OFF); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_OFF)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_VERTICAL)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL)); + EXPECT_TRUE(context.sut.traits().supports_swing_mode(climate::CLIMATE_SWING_BOTH)); } } // namespace esphome::mitsubishi_cn105::testing diff --git a/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_swing_mode_manager_tests.cpp b/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_swing_mode_manager_tests.cpp new file mode 100644 index 0000000000..ab3048b874 --- /dev/null +++ b/tests/components/mitsubishi_cn105/climate/mitsubishi_cn105_swing_mode_manager_tests.cpp @@ -0,0 +1,99 @@ +#include "../common.h" + +#include "esphome/components/mitsubishi_cn105/mitsubishi_cn105_swing_mode_manager.h" + +namespace esphome::mitsubishi_cn105::testing { + +static SwingModeManager make_swing_mode_manager(std::initializer_list supported_modes) { + SwingModeManager manager; + climate::ClimateSwingModeMask supported_swing_modes; + for (const auto mode : supported_modes) + supported_swing_modes.insert(mode); + manager.set_supported_swing_modes(supported_swing_modes); + return manager; +} + +TEST(SwingModeManagerTests, StatusMapsVerticalSwingWhenSupported) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}); + EXPECT_EQ(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::SWING, MitsubishiCN105::WideVaneMode::CENTER), + std::optional{climate::CLIMATE_SWING_VERTICAL}); +} + +TEST(SwingModeManagerTests, StatusMapsHorizontalSwingWhenSupported) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL}); + EXPECT_EQ(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::AUTO, MitsubishiCN105::WideVaneMode::SWING), + std::optional{climate::CLIMATE_SWING_HORIZONTAL}); +} + +TEST(SwingModeManagerTests, StatusMapsBothSwingWhenSupported) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}); + EXPECT_EQ(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::SWING, MitsubishiCN105::WideVaneMode::SWING), + std::optional{climate::CLIMATE_SWING_BOTH}); +} + +TEST(SwingModeManagerTests, StatusMapsSwingOffWhenNoSwingActive) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}); + EXPECT_EQ( + manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::POSITION_3, MitsubishiCN105::WideVaneMode::CENTER), + std::optional{climate::CLIMATE_SWING_OFF}); +} + +TEST(SwingModeManagerTests, RemembersLastNonSwingPositions) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}); + manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::POSITION_4, MitsubishiCN105::WideVaneMode::RIGHT); + manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::SWING, MitsubishiCN105::WideVaneMode::SWING); + EXPECT_EQ(manager.vane_from(climate::CLIMATE_SWING_OFF), std::optional{MitsubishiCN105::VaneMode::POSITION_4}); + EXPECT_EQ(manager.wide_vane_from(climate::CLIMATE_SWING_OFF), std::optional{MitsubishiCN105::WideVaneMode::RIGHT}); +} + +TEST(SwingModeManagerTests, UnknownValuesDoNotOverwriteRememberedPositions) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}); + manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::POSITION_2, MitsubishiCN105::WideVaneMode::LEFT); + manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::UNKNOWN, MitsubishiCN105::WideVaneMode::UNKNOWN); + EXPECT_EQ(manager.vane_from(climate::CLIMATE_SWING_OFF), std::optional{MitsubishiCN105::VaneMode::POSITION_2}); + EXPECT_EQ(manager.wide_vane_from(climate::CLIMATE_SWING_OFF), std::optional{MitsubishiCN105::WideVaneMode::LEFT}); +} + +TEST(SwingModeManagerTests, UnsupportedVerticalSwingStateIsIgnored) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL}); + EXPECT_EQ(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::SWING, MitsubishiCN105::WideVaneMode::CENTER), + std::optional{climate::CLIMATE_SWING_OFF}); +} + +TEST(SwingModeManagerTests, UnsupportedHorizontalSwingStateIsIgnored) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}); + EXPECT_EQ(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::AUTO, MitsubishiCN105::WideVaneMode::SWING), + std::optional{climate::CLIMATE_SWING_OFF}); +} + +TEST(SwingModeManagerTests, SwingModeFromReturnsNulloptWhenNoSwingModesSupported) { + auto manager = make_swing_mode_manager({}); + EXPECT_FALSE(manager.update_and_get_swing_mode(MitsubishiCN105::VaneMode::SWING, MitsubishiCN105::WideVaneMode::SWING) + .has_value()); +} + +TEST(SwingModeManagerTests, VaneFromSwingModeReturnsNulloptWhenVerticalUnsupported) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL}); + EXPECT_FALSE(manager.vane_from(climate::CLIMATE_SWING_VERTICAL).has_value()); +} + +TEST(SwingModeManagerTests, WideVaneFromSwingModeReturnsNulloptWhenHorizontalUnsupported) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}); + EXPECT_FALSE(manager.wide_vane_from(climate::CLIMATE_SWING_HORIZONTAL).has_value()); +} + +TEST(SwingModeManagerTests, VaneAndWideVaneFromSwingModeMapSwingModes) { + auto manager = make_swing_mode_manager({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, + climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}); + EXPECT_EQ(manager.vane_from(climate::CLIMATE_SWING_VERTICAL), std::optional{MitsubishiCN105::VaneMode::SWING}); + EXPECT_EQ(manager.vane_from(climate::CLIMATE_SWING_BOTH), std::optional{MitsubishiCN105::VaneMode::SWING}); + EXPECT_EQ(manager.wide_vane_from(climate::CLIMATE_SWING_HORIZONTAL), + std::optional{MitsubishiCN105::WideVaneMode::SWING}); + EXPECT_EQ(manager.wide_vane_from(climate::CLIMATE_SWING_BOTH), std::optional{MitsubishiCN105::WideVaneMode::SWING}); +} + +} // namespace esphome::mitsubishi_cn105::testing diff --git a/tests/components/mitsubishi_cn105/common.h b/tests/components/mitsubishi_cn105/common.h index ee287d2548..6029327e9a 100644 --- a/tests/components/mitsubishi_cn105/common.h +++ b/tests/components/mitsubishi_cn105/common.h @@ -64,26 +64,4 @@ class TestableMitsubishiCN105 : public MitsubishiCN105 { void set_current_time(uint32_t ms) { test_loop_time_ms = ms; } }; -class TestableMitsubishiCN105Climate : public MitsubishiCN105Climate { - public: - TestableMitsubishiCN105Climate() { this->set_parent(&this->component_); } - - using MitsubishiCN105Climate::apply_values_; - using MitsubishiCN105Climate::last_non_swing_vane_mode_; - using MitsubishiCN105Climate::last_non_swing_wide_vane_mode_; - - MitsubishiCN105::Status &status() { return const_cast(this->component_.status()); } - void set_use_fahrenheit(bool value) { this->component_.set_use_fahrenheit(value); } - - protected: - MitsubishiCN105Component component_; -}; - -class TestableMitsubishiCN105Component : public MitsubishiCN105Component { - public: - MitsubishiCN105::Status &mutable_status() { return const_cast(this->status()); } - - void notify_status() { this->status_callback_.call(); } -}; - } // namespace esphome::mitsubishi_cn105::testing diff --git a/tests/components/mitsubishi_cn105/mitsubishi_cn105_component_tests.cpp b/tests/components/mitsubishi_cn105/mitsubishi_cn105_component_tests.cpp index c957759223..928d4123f6 100644 --- a/tests/components/mitsubishi_cn105/mitsubishi_cn105_component_tests.cpp +++ b/tests/components/mitsubishi_cn105/mitsubishi_cn105_component_tests.cpp @@ -3,7 +3,7 @@ namespace esphome::mitsubishi_cn105::testing { TEST(MitsubishiCN105ComponentTests, PublishesVaneStateForEveryValidSnapshot) { - TestableMitsubishiCN105Component hub; + MitsubishiCN105Component hub; size_t callback_count = 0; std::optional callback_direction; hub.add_on_vane_state_callback([&](const VaneState &state) { @@ -11,8 +11,9 @@ TEST(MitsubishiCN105ComponentTests, PublishesVaneStateForEveryValidSnapshot) { callback_direction = state.vertical.direction; }); - hub.mutable_status().room_temperature = 20.0f; - hub.mutable_status().vane_mode = MitsubishiCN105::VaneMode::POSITION_4; + hub.set_telemetry_request_min_interval(SCHEDULER_DONT_RUN); + hub.set_target_temperature(20.0f); + hub.set_vane_mode(MitsubishiCN105::VaneMode::POSITION_4); hub.publish_status(); EXPECT_EQ(callback_count, 1); @@ -25,7 +26,7 @@ TEST(MitsubishiCN105ComponentTests, PublishesVaneStateForEveryValidSnapshot) { } TEST(MitsubishiCN105ComponentTests, PublishesUnknownVaneState) { - TestableMitsubishiCN105Component hub; + MitsubishiCN105Component hub; size_t status_callback_count = 0; size_t vane_callback_count = 0; std::optional callback_direction; @@ -35,15 +36,16 @@ TEST(MitsubishiCN105ComponentTests, PublishesUnknownVaneState) { callback_direction = state.vertical.direction; }); - hub.mutable_status().room_temperature = 20.0f; - hub.mutable_status().vane_mode = MitsubishiCN105::VaneMode::UNKNOWN; + hub.set_telemetry_request_min_interval(SCHEDULER_DONT_RUN); + hub.set_target_temperature(20.0f); + ASSERT_EQ(hub.status().vane_mode, MitsubishiCN105::VaneMode::UNKNOWN); hub.publish_status(); EXPECT_EQ(status_callback_count, 1); EXPECT_EQ(vane_callback_count, 1); EXPECT_EQ(callback_direction, std::optional{VERTICAL_VANE_MODE_UNKNOWN}); - hub.mutable_status().vane_mode = MitsubishiCN105::VaneMode::POSITION_4; + hub.set_vane_mode(MitsubishiCN105::VaneMode::POSITION_4); hub.publish_status(); EXPECT_EQ(status_callback_count, 2); @@ -52,7 +54,7 @@ TEST(MitsubishiCN105ComponentTests, PublishesUnknownVaneState) { } TEST(MitsubishiCN105ComponentTests, VaneCallAppliesVerticalDirection) { - TestableMitsubishiCN105Component hub; + MitsubishiCN105Component hub; auto call = hub.make_vane_call(); call.vertical.set_direction(VERTICAL_VANE_MODE_POSITION_5); @@ -62,12 +64,11 @@ TEST(MitsubishiCN105ComponentTests, VaneCallAppliesVerticalDirection) { } TEST(MitsubishiCN105ComponentTests, VaneControlActionAppliesConfiguredFields) { - TestableMitsubishiCN105Component hub; + MitsubishiCN105Component hub; VaneControlAction<> action(&hub, [](VaneCall &call) { call.vertical.set_direction(VERTICAL_VANE_MODE_SWING); }); action.play(); EXPECT_EQ(hub.status().vane_mode, MitsubishiCN105::VaneMode::SWING); } - } // namespace esphome::mitsubishi_cn105::testing diff --git a/tests/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical_tests.cpp b/tests/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical_tests.cpp index 1f928e3bf4..55ae1d6c92 100644 --- a/tests/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical_tests.cpp +++ b/tests/components/mitsubishi_cn105/select/mitsubishi_cn105_vane_select_vertical_tests.cpp @@ -3,14 +3,9 @@ namespace esphome::mitsubishi_cn105::testing { -class TestableMitsubishiCN105VerticalVaneDirectionSelect : public MitsubishiCN105VerticalVaneDirectionSelect { - public: - using MitsubishiCN105VerticalVaneDirectionSelect::control; -}; - struct VerticalVaneDirectionSelectTestContext { - TestableMitsubishiCN105Component hub; - TestableMitsubishiCN105VerticalVaneDirectionSelect select; + MitsubishiCN105Component hub; + MitsubishiCN105VerticalVaneDirectionSelect select; VerticalVaneDirectionSelectTestContext() { this->select.traits.set_options({"Auto", "1", "2", "3", "4", "5", "Swing"}); @@ -31,13 +26,15 @@ TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, MapsIndexesToVaneModes) { for (size_t i = 0; i < expected_modes.size(); ++i) { SCOPED_TRACE(i); - ctx.select.control(i); + ctx.select.make_call().set_index(i).perform(); EXPECT_EQ(ctx.hub.status().vane_mode, expected_modes[i]); } } TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, PublishesIncomingVaneModes) { VerticalVaneDirectionSelectTestContext ctx; + ctx.hub.set_telemetry_request_min_interval(SCHEDULER_DONT_RUN); + ctx.hub.set_target_temperature(20.0f); constexpr std::array modes{ MitsubishiCN105::VaneMode::AUTO, MitsubishiCN105::VaneMode::POSITION_1, @@ -48,13 +45,12 @@ TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, PublishesIncomingVaneModes for (size_t i = 0; i < modes.size(); ++i) { SCOPED_TRACE(i); - ctx.hub.mutable_status().vane_mode = modes[i]; - ctx.hub.notify_status(); + ctx.hub.set_vane_mode(modes[i]); + ctx.hub.publish_status(); EXPECT_EQ(ctx.select.active_index(), std::optional{i}); } - ctx.hub.mutable_status().vane_mode = MitsubishiCN105::VaneMode::UNKNOWN; - ctx.hub.notify_status(); + ctx.select.publish_vane_state(MitsubishiCN105::VaneMode::UNKNOWN); EXPECT_EQ(ctx.select.active_index(), std::optional{modes.size() - 1}); } @@ -64,14 +60,15 @@ TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, ControlPublishesSelectAndC climate_entity.set_parent(&ctx.hub); climate_entity.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); - ctx.hub.mutable_status().room_temperature = 20.0f; + ctx.hub.set_telemetry_request_min_interval(SCHEDULER_DONT_RUN); + ctx.hub.set_target_temperature(20.0f); climate_entity.setup(); - ctx.select.control(6); + ctx.select.make_call().set_index(6).perform(); EXPECT_EQ(ctx.select.active_index(), std::optional{6}); EXPECT_EQ(climate_entity.swing_mode, climate::CLIMATE_SWING_VERTICAL); - ctx.select.control(3); + ctx.select.make_call().set_index(3).perform(); EXPECT_EQ(ctx.select.active_index(), std::optional{3}); EXPECT_EQ(climate_entity.swing_mode, climate::CLIMATE_SWING_OFF); } @@ -82,7 +79,8 @@ TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, ClimateControlPublishesSel climate_entity.set_parent(&ctx.hub); climate_entity.set_supported_swing_mode(climate::CLIMATE_SWING_VERTICAL); - ctx.hub.mutable_status().room_temperature = 20.0f; + ctx.hub.set_telemetry_request_min_interval(SCHEDULER_DONT_RUN); + ctx.hub.set_target_temperature(20.0f); climate_entity.setup(); climate_entity.make_call().set_swing_mode(climate::CLIMATE_SWING_VERTICAL).perform(); @@ -95,10 +93,9 @@ TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, ClimateControlPublishesSel TEST(MitsubishiCN105VerticalVaneDirectionSelectTests, BeforeInitializationDoesNotPublishSelectState) { VerticalVaneDirectionSelectTestContext ctx; - ctx.select.control(3); + ctx.select.make_call().set_index(3).perform(); EXPECT_EQ(ctx.hub.status().vane_mode, MitsubishiCN105::VaneMode::POSITION_3); EXPECT_FALSE(ctx.select.has_state()); } - } // namespace esphome::mitsubishi_cn105::testing