using Azimuth; using System; using System.Collections.Generic; using Glass.Typesetting; using UnitTestSharp; namespace Glass.UnitTests.Typesetting { public class KerningTableTests : TestFixture { private static Dictionary<(short Left, short Right), short> Kernings( params ((short Left, short Right) Pair, short Amount)[] entries) { var result = new Dictionary<(short, short), short>(); foreach (((short Left, short Right) pair, short amount) in entries) { result[pair] = amount; } return result; } private static Scalar Amount(KerningTable table, char left, char right) => table.SpaceBetweenClasses(table.LeftClassOf(left), table.RightClassOf(right)); public class BuildTests : TestFixture { public void NullKernings_Throws() { CheckThrow(typeof(ArgumentNullException)); KerningTable.Build(null); } } public class LeftClassOfTests : TestFixture { public void GlyphsSharingARow_ShareAClass() { KerningTable table = KerningTable.Build(Kernings( (((short)'A', (short)'V'), (short)-2), (((short)'B', (short)'V'), (short)-2))); CheckEqual(table.LeftClassOf('A'), table.LeftClassOf('B')); } public void GlyphNeverSeen_IsNone() { KerningTable table = KerningTable.Build(Kernings()); CheckEqual(KerningClass.None, table.LeftClassOf('A')); } } public class RightClassOfTests : TestFixture { public void GlyphNeverSeen_IsNone() { KerningTable table = KerningTable.Build(Kernings()); CheckEqual(KerningClass.None, table.RightClassOf('A')); } } public class IndexOfTests : TestFixture { public void IsTheLeftClassesRow_ThenTheRightClassesColumn() { CheckEqual(2 * 5 + 3, KerningTable.IndexOf((KerningClass)2, (KerningClass)3, columns: 5)); } } public class ColumnsTests : TestFixture { public void IsHowManyRightClassesThereAre_CountingNone() { KerningTable table = KerningTable.Build(Kernings( (((short)'A', (short)'V'), (short)-2), (((short)'A', (short)'W'), (short)-1))); CheckEqual(3, table.Columns); } } public class MatrixTests : TestFixture { public void HoldsARowOfColumnsForEachLeftClass_CountingNone() { KerningTable table = KerningTable.Build(Kernings( (((short)'A', (short)'V'), (short)-2), (((short)'A', (short)'W'), (short)-1), (((short)'B', (short)'V'), (short)-3))); CheckEqual(3 * table.Columns, table.Matrix.Length); } public void HoldsEachPairsKerningAtItsIndex() { KerningTable table = KerningTable.Build(Kernings((((short)'A', (short)'V'), (short)-2))); CheckEqual((short)-2, table.Matrix[KerningTable.IndexOf(table.LeftClassOf('A'), table.RightClassOf('V'), table.Columns)]); } } public class SpaceBetweenClassesTests : TestFixture { public void ReturnsTheKernedAmount() { KerningTable table = KerningTable.Build(Kernings((((short)'A', (short)'V'), (short)-2))); CheckEqual(-2, Amount(table, 'A', 'V')); } public void NoEntry_IsZero() { KerningTable table = KerningTable.Build(Kernings()); CheckEqual(0, Amount(table, 'A', 'V')); } public void IsDirectional() { KerningTable table = KerningTable.Build(Kernings((((short)'A', (short)'V'), (short)-2))); CheckEqual(0, Amount(table, 'V', 'A')); } public void GlyphsSharingAClass_BothResolveTheSameWay() { // 'A' and 'B' kern identically against 'V', so they land in the same left class. KerningTable table = KerningTable.Build(Kernings( (((short)'A', (short)'V'), (short)-2), (((short)'B', (short)'V'), (short)-2))); CheckEqual(-2, Amount(table, 'A', 'V')); CheckEqual(-2, Amount(table, 'B', 'V')); } public void WideCodepoints_Resolve() { KerningTable table = KerningTable.Build(Kernings((((short)0x2019, (short)'s'), (short)-3))); CheckEqual(-3, Amount(table, (char)0x2019, 's')); } public void CodepointBeyondAnyKernedGlyph_IsZero() { KerningTable table = KerningTable.Build(Kernings((((short)'A', (short)'V'), (short)-2))); CheckEqual(0, Amount(table, (char)0xFFFF, 'A')); } public void ValueOutsideSbyteRange_StillResolves() { KerningTable table = KerningTable.Build(Kernings((((short)'A', (short)'V'), (short)-200))); CheckEqual(-200, Amount(table, 'A', 'V')); } public void NegativeInt16Codepoint_UnwrapsToTheHighUnicodeChar() { // Codepoints past 32767 are stored as a negative Int16 -- (short)-1 is codepoint 0xFFFF. KerningTable table = KerningTable.Build(Kernings((((short)-1, (short)'A'), (short)5))); CheckEqual(5, Amount(table, (char)0xFFFF, 'A')); } } } }