Skip to content

Commit abcf56b

Browse files
committed
web: add tests for GlyphCache and getBounds label margin
GlyphCache unit tests verify: - textWidth/textHeight return positive values - Printable ASCII glyphs return valid alpha bitmaps - Anti-aliased pixels exist (alpha values between 1-254) - Proportional widths (W wider than i with DejaVu Sans) - Case preserved (a and A produce different bitmaps) - Different font heights produce different cell heights TileGenerator test verifies getBounds() margin is larger than pin_max_size when BTerms exist (accounts for label text width). Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
1 parent 812fb80 commit abcf56b

3 files changed

Lines changed: 156 additions & 0 deletions

File tree

src/web/test/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,18 @@ cc_test(
253253
],
254254
)
255255

256+
cc_test(
257+
name = "glyph_cache_test",
258+
srcs = ["cpp/TestGlyphCache.cpp"],
259+
copts = ["-Isrc/web/src"],
260+
features = ["-layering_check"],
261+
deps = [
262+
"//src/web",
263+
"@googletest//:gtest",
264+
"@googletest//:gtest_main",
265+
],
266+
)
267+
256268
cc_test(
257269
name = "debug_graphics_test",
258270
srcs = ["cpp/TestDebugGraphics.cpp"],
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) 2026, The OpenROAD Authors
3+
4+
#include <gtest/gtest.h>
5+
6+
#include "glyph_cache.h"
7+
8+
namespace web {
9+
namespace {
10+
11+
TEST(GlyphCacheTest, TextWidthPositive)
12+
{
13+
EXPECT_GT(glyphCache().textWidth("hello", 14), 0);
14+
}
15+
16+
TEST(GlyphCacheTest, TextWidthEmpty)
17+
{
18+
EXPECT_EQ(glyphCache().textWidth("", 14), 0);
19+
}
20+
21+
TEST(GlyphCacheTest, TextHeightPositive)
22+
{
23+
EXPECT_GT(glyphCache().textHeight(14), 0);
24+
}
25+
26+
TEST(GlyphCacheTest, GlyphReturnsAlpha)
27+
{
28+
// Every printable ASCII char should have a non-null bitmap
29+
// (except space which has no visible pixels).
30+
for (char ch = '!'; ch <= '~'; ++ch) {
31+
auto gi = glyphCache().glyph(14, ch);
32+
EXPECT_NE(gi.alpha, nullptr) << "char '" << ch << "'";
33+
EXPECT_GT(gi.bmp_width, 0) << "char '" << ch << "'";
34+
EXPECT_GT(gi.bmp_height, 0) << "char '" << ch << "'";
35+
EXPECT_GT(gi.advance, 0) << "char '" << ch << "'";
36+
}
37+
}
38+
39+
TEST(GlyphCacheTest, SpaceHasNoPixels)
40+
{
41+
auto gi = glyphCache().glyph(14, ' ');
42+
EXPECT_EQ(gi.alpha, nullptr);
43+
EXPECT_GT(gi.advance, 0); // space still has an advance
44+
}
45+
46+
TEST(GlyphCacheTest, GlyphOutOfRange)
47+
{
48+
auto gi = glyphCache().glyph(14, '\n');
49+
EXPECT_EQ(gi.alpha, nullptr);
50+
51+
auto gi2 = glyphCache().glyph(14, '\x7f'); // DEL
52+
EXPECT_EQ(gi2.alpha, nullptr);
53+
}
54+
55+
TEST(GlyphCacheTest, AntiAliasedPixels)
56+
{
57+
// A rendered glyph should contain alpha values between 1 and 254
58+
// (anti-aliased edges), not just binary 0/255.
59+
auto gi = glyphCache().glyph(20, 'O');
60+
ASSERT_NE(gi.alpha, nullptr);
61+
bool found_intermediate = false;
62+
for (int i = 0; i < gi.bmp_width * gi.bmp_height; ++i) {
63+
if (gi.alpha[i] > 0 && gi.alpha[i] < 255) {
64+
found_intermediate = true;
65+
break;
66+
}
67+
}
68+
EXPECT_TRUE(found_intermediate) << "No anti-aliased pixels found in 'O'";
69+
}
70+
71+
TEST(GlyphCacheTest, ProportionalWidths)
72+
{
73+
// DejaVu Sans is proportional — 'W' should be wider than 'i'.
74+
const int w_width = glyphCache().textWidth("W", 14);
75+
const int i_width = glyphCache().textWidth("i", 14);
76+
EXPECT_GT(w_width, i_width);
77+
}
78+
79+
TEST(GlyphCacheTest, DifferentSizes)
80+
{
81+
EXPECT_LT(glyphCache().cellHeight(10), glyphCache().cellHeight(20));
82+
}
83+
84+
TEST(GlyphCacheTest, CasePreserved)
85+
{
86+
// 'a' and 'A' should produce different bitmaps.
87+
auto lower = glyphCache().glyph(14, 'a');
88+
auto upper = glyphCache().glyph(14, 'A');
89+
ASSERT_NE(lower.alpha, nullptr);
90+
ASSERT_NE(upper.alpha, nullptr);
91+
// At minimum, the bitmap dimensions or content should differ.
92+
bool differ = (lower.bmp_width != upper.bmp_width)
93+
|| (lower.bmp_height != upper.bmp_height);
94+
if (!differ) {
95+
// Same dimensions — compare content.
96+
for (int i = 0; i < lower.bmp_width * lower.bmp_height; ++i) {
97+
if (lower.alpha[i] != upper.alpha[i]) {
98+
differ = true;
99+
break;
100+
}
101+
}
102+
}
103+
EXPECT_TRUE(differ) << "'a' and 'A' glyphs should differ";
104+
}
105+
106+
TEST(GlyphCacheTest, TextWidthIncludesAllChars)
107+
{
108+
// Width of "ab" should be greater than width of "a".
109+
const int w1 = glyphCache().textWidth("a", 14);
110+
const int w2 = glyphCache().textWidth("ab", 14);
111+
EXPECT_GT(w2, w1);
112+
}
113+
114+
} // namespace
115+
} // namespace web

src/web/test/cpp/TestTileGenerator.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,35 @@ TEST_F(TileGeneratorTest, GetBoundsReflectsInstances)
9595
EXPECT_LE(bounds.yMin(), 10000);
9696
}
9797

98+
TEST_F(TileGeneratorTest, BoundsIncludeLabelMargin)
99+
{
100+
// Place instances to fill the BBox across the die.
101+
placeInst("BUF_X16", "buf_ll", 0, 0);
102+
placeInst("BUF_X16", "buf_ur", 90000, 90000);
103+
104+
// Create a BTerm pin at the right die edge.
105+
const char* pin_name = "my_long_pin_name";
106+
odb::dbNet* net = odb::dbNet::create(block_, pin_name);
107+
odb::dbBTerm* bterm = odb::dbBTerm::create(net, pin_name);
108+
bterm->setIoType(odb::dbIoType::INPUT);
109+
odb::dbBPin* bpin = odb::dbBPin::create(bterm);
110+
odb::dbTechLayer* m1 = getDb()->getTech()->findLayer("metal1");
111+
ASSERT_NE(m1, nullptr);
112+
// Place at right die edge (x=99800..100000).
113+
odb::dbBox::create(bpin, m1, 99800, 50000, 100000, 50200);
114+
bpin->setPlacementStatus(odb::dbPlacementStatus::PLACED);
115+
116+
makeTileGen();
117+
const odb::Rect die = block_->getDieArea();
118+
const odb::Rect bounds = tile_gen_->getBounds();
119+
120+
// The margin should be larger than just the pin marker size,
121+
// because it now accounts for the label text width.
122+
const int pin_max = tile_gen_->getPinMaxSize();
123+
const int margin = bounds.xMax() - die.xMax();
124+
EXPECT_GT(margin, pin_max);
125+
}
126+
98127
TEST_F(TileGeneratorTest, GetLayers)
99128
{
100129
makeTileGen();

0 commit comments

Comments
 (0)