diff --git a/lib/board/draw.c b/lib/board/draw.c index a303c7ef2..cb45fb39b 100644 --- a/lib/board/draw.c +++ b/lib/board/draw.c @@ -212,7 +212,11 @@ static bool draw_string_walk(Canvas* canvas, const Font* font, char_params.x = x_offset + p->x; have_space = draw_char_impl(canvas, &char_params, &x_offset, NULL, img, measure); - str_write++; + /* A rejected glyph was not drawn. Leave str_write on it so the caller's + * completeness result cannot report that a clipped final glyph fitted. */ + if (have_space) { + str_write++; + } } if (!measure) { diff --git a/unittests/board/board.cpp b/unittests/board/board.cpp index b10cfdb81..e23b7cb04 100644 --- a/unittests/board/board.cpp +++ b/unittests/board/board.cpp @@ -65,6 +65,18 @@ TEST_F(BodyFits, ConfirmBodyFits) { const std::string eighty_w(80, 'W'); EXPECT_TRUE(confirm_body_fits(eighty_w.c_str(), BODY_WIDTH)); EXPECT_FALSE(confirm_body_fits(eighty_w.c_str(), BODY_WIDTH_WITH_ICON)); + + // Regression: draw_string_walk() advanced str_write unconditionally, so a + // REJECTED final glyph was still consumed and the walk then saw '\0' and + // reported that everything fitted. The failure is exactly one glyph wide, + // which is why the earlier three-way sweep of 3,510 bodies missed it: it only + // shows at the precise boundary. 117 digits fill three rows; the 118th is the + // first glyph that cannot be placed and must be reported as not fitting. + std::string digits; + for (size_t i = 0; i < 118; i++) digits += "0123456789"[i % 10]; + EXPECT_TRUE(confirm_body_fits(digits.substr(0, 117).c_str(), BODY_WIDTH)); + EXPECT_FALSE(confirm_body_fits(digits.c_str(), BODY_WIDTH)) + << "a body overflowing by exactly one glyph must not report as fitting"; } // Regression: calc_str_line() accumulated into a uint8_t while returning