using System.Collections.Generic;
using AcDream.App.UI;
using DatReaderWriter.Types;
namespace AcDream.App.Tests.UI;
///
/// Pure pen-advance / MeasureWidth math for the retail dat font (no GL, no dat).
/// The advance per glyph is the retail
/// HorizontalOffsetBefore + Width + HorizontalOffsetAfter
/// (SurfaceWindow::DrawCharacter, acclient 0x00442c3a), accumulated across the
/// string the way the retail string loop does (0x00467ed4 edi_3 += var_98).
///
public class UiDatFontTests
{
private static FontCharDesc Glyph(
ushort unicode, byte width,
sbyte before = 0, sbyte after = 0,
ushort offsetX = 0, ushort offsetY = 0, byte height = 16, sbyte vBefore = 0)
=> new()
{
Unicode = unicode,
Width = width,
Height = height,
OffsetX = offsetX,
OffsetY = offsetY,
HorizontalOffsetBefore = before,
HorizontalOffsetAfter = after,
VerticalOffsetBefore = vBefore,
};
[Fact]
public void GlyphAdvance_SumsBeforeWidthAfter()
{
var g = Glyph('A', width: 8, before: 1, after: 2);
Assert.Equal(11f, UiDatFont.GlyphAdvance(g));
}
[Fact]
public void GlyphAdvance_HandlesNegativeBearings()
{
// Kerned glyph: a negative left-bearing pulls it leftward; the advance
// still nets out to before + width + after.
var g = Glyph('j', width: 4, before: -1, after: 0);
Assert.Equal(3f, UiDatFont.GlyphAdvance(g));
}
[Fact]
public void MeasureWidth_SumsEachGlyphAdvance()
{
var table = new Dictionary
{
['2'] = Glyph('2', width: 7, before: 1, after: 1), // advance 9
['9'] = Glyph('9', width: 7, before: 1, after: 1), // advance 9
['1'] = Glyph('1', width: 3, before: 2, after: 1), // advance 6
['/'] = Glyph('/', width: 4, before: 0, after: 1), // advance 5
};
FontCharDesc? Lookup(char c) => table.TryGetValue(c, out var g) ? g : null;
// "291/291" = 9 + 9 + 6 + 5 + 9 + 9 + 6 = 53
Assert.Equal(53f, UiDatFont.MeasureWidth("291/291", Lookup));
}
[Fact]
public void MeasureWidth_SkipsCharactersNotInFont()
{
var table = new Dictionary
{
['5'] = Glyph('5', width: 6, before: 1, after: 1), // advance 8
};
FontCharDesc? Lookup(char c) => table.TryGetValue(c, out var g) ? g : null;
// 'X' has no glyph → contributes nothing; only the two '5's count.
Assert.Equal(16f, UiDatFont.MeasureWidth("5X5", Lookup));
}
[Fact]
public void MeasureWidth_EmptyOrNullIsZero()
{
FontCharDesc? Lookup(char c) => null;
Assert.Equal(0f, UiDatFont.MeasureWidth("", Lookup));
Assert.Equal(0f, UiDatFont.MeasureWidth(null, Lookup));
}
}