diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index f006c64be76..ba8f85463f4 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -843,7 +843,6 @@ constexpr uint8_t TESTCARD_FONT[3][8] PROGMEM = {{0x41, 0x7F, 0x7F, 0x09, 0x19, void Display::test_card() { int w = get_width(), h = get_height(), image_w, image_h; this->clear(); - this->show_test_card_ = false; image_w = std::min(w - 20, 310); image_h = std::min(h - 20, 255); int shift_x = (w - image_w) / 2; diff --git a/esphome/components/mipi_spi/mipi_spi.h b/esphome/components/mipi_spi/mipi_spi.h index 3a772862f31..f55ae723780 100644 --- a/esphome/components/mipi_spi/mipi_spi.h +++ b/esphome/components/mipi_spi/mipi_spi.h @@ -570,12 +570,12 @@ class MipiSpiBuffer if (this->auto_clear_enabled_) { this->clear(); } - if (this->page_ != nullptr) { + if (this->show_test_card_) { + this->test_card(); + } else if (this->page_ != nullptr) { this->page_->get_writer()(*this); } else if (this->writer_.has_value()) { (*this->writer_)(*this); - } else { - this->test_card(); } #if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE esph_log_v(TAG, "Drawing from line %d took %dms", this->start_line_, millis() - lap); diff --git a/tests/components/display/test_test_card.cpp b/tests/components/display/test_test_card.cpp new file mode 100644 index 00000000000..555611bc093 --- /dev/null +++ b/tests/components/display/test_test_card.cpp @@ -0,0 +1,80 @@ +#include + +#include +#include +#include +#include + +#include "esphome/components/display/display.h" +#include "esphome/core/application.h" + +namespace esphome::display::testing { + +// Records the colour of every pixel written, so a drawn test card shows up as non-black pixels. +class TestCardDisplay : public Display { + public: + void draw_pixel_at(int x, int y, Color color) override { this->colors_.push_back(color.raw_32); } + void update() override { this->do_update_(); } + DisplayType get_display_type() override { return DisplayType::DISPLAY_TYPE_COLOR; } + + bool drew_test_card() const { + return std::any_of(this->colors_.begin(), this->colors_.end(), [](uint32_t c) { return c != 0; }); + } + void reset() { this->colors_.clear(); } + + protected: + int get_width_internal() override { return 64; } + int get_height_internal() override { return 64; } + std::vector colors_; +}; + +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_++; }; + } +}; +} // namespace + +TEST_F(TestCard, DrawnOnEveryUpdateInsteadOfLambda) { + TestCardDisplay display; + display.set_writer(this->count_writer_()); + display.show_test_card(); + for (int i = 0; i != 3; i++) { + display.reset(); + display.update(); + EXPECT_TRUE(display.drew_test_card()) << "update " << i; + } + EXPECT_EQ(this->writer_calls_, 0); +} + +TEST_F(TestCard, DrawnOnEveryUpdateInsteadOfPages) { + TestCardDisplay display; + DisplayPage page(this->count_writer_()); + display.set_pages({&page}); + display.show_test_card(); + for (int i = 0; i != 3; i++) { + display.reset(); + display.update(); + EXPECT_TRUE(display.drew_test_card()) << "update " << i; + } + EXPECT_EQ(this->writer_calls_, 0); +} + +TEST_F(TestCard, LambdaRunsWithoutTestCard) { + TestCardDisplay display; + display.set_writer(this->count_writer_()); + display.update(); + display.update(); + EXPECT_FALSE(display.drew_test_card()); + EXPECT_EQ(this->writer_calls_, 2); +} + +} // namespace esphome::display::testing