using System; using System.Runtime.InteropServices; using System.Text; using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Visuals.UnitTests.Media.TextFormatting; using Xunit; using Xunit.Abstractions; namespace Avalonia.Base.UnitTests.Media.TextFormatting { /// /// This class is intended for use when the Unicode spec changes. Otherwise the containing tests are redundant. /// To update the GraphemeBreak.trie run the test. /// public class GraphemeBreakClassTrieGeneratorTests { private readonly ITestOutputHelper _outputHelper; public GraphemeBreakClassTrieGeneratorTests(ITestOutputHelper outputHelper) { _outputHelper = outputHelper; } [Fact(Skip = "Only run when we update the trie.")] public void Should_Enumerate() { var generator = new GraphemeBreakTestDataGenerator(); foreach (var testData in generator) { Assert.True(Run(testData)); } } private bool Run(GraphemeBreakData t) { var text = Encoding.UTF32.GetString(MemoryMarshal.Cast(t.Codepoints).ToArray()); var grapheme = Encoding.UTF32.GetString(MemoryMarshal.Cast(t.Grapheme).ToArray()).AsSpan(); var enumerator = new GraphemeEnumerator(text); enumerator.MoveNext(out var g); var actual = text.AsSpan(g.Offset, g.Length); bool pass = actual.Length == grapheme.Length; if (pass) { for (int i = 0; i < grapheme.Length; i++) { var a = grapheme[i]; var b = actual[i]; if (a != b) { pass = false; break; } } } if (!pass) { _outputHelper.WriteLine($"Failed line {t.LineNumber}"); _outputHelper.WriteLine($" Text: {text}"); _outputHelper.WriteLine($" Codepoints: {string.Join(" ", t.Codepoints)}"); _outputHelper.WriteLine($" Grapheme: {string.Join(" ", t.Grapheme)}"); _outputHelper.WriteLine($" Line: {t.Line}"); return false; } return true; } [Fact(Skip = "Only run when we update the trie.")] public void Should_Enumerate_Other() { const string text = "ABCDEFGHIJ"; var enumerator = new GraphemeEnumerator(text); var count = 0; while (enumerator.MoveNext(out var grapheme)) { Assert.Equal(1, grapheme.Length); count++; } Assert.Equal(10, count); } [Fact(Skip = "Only run when we update the trie.")] public void Should_Generate_Trie() { GraphemeBreakClassTrieGenerator.Execute(); } } }