| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Net.Http;
- using Avalonia.Media.TextFormatting.Unicode;
- using Xunit;
- using Xunit.Abstractions;
- namespace Avalonia.Base.UnitTests.Media.TextFormatting
- {
- public class LineBreakEnumeratorTests
- {
- private readonly ITestOutputHelper _outputHelper;
-
- public LineBreakEnumeratorTests(ITestOutputHelper outputHelper)
- {
- _outputHelper = outputHelper;
- }
-
- [Fact]
- public void BasicLatinTest()
- {
- var lineBreaker = new LineBreakEnumerator("Hello World\r\nThis is a test.".AsMemory());
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(6, lineBreaker.Current.PositionWrap);
- Assert.False(lineBreaker.Current.Required);
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(13, lineBreaker.Current.PositionWrap);
- Assert.True(lineBreaker.Current.Required);
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(18, lineBreaker.Current.PositionWrap);
- Assert.False(lineBreaker.Current.Required);
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(21, lineBreaker.Current.PositionWrap);
- Assert.False(lineBreaker.Current.Required);
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(23, lineBreaker.Current.PositionWrap);
- Assert.False(lineBreaker.Current.Required);
- Assert.True(lineBreaker.MoveNext());
- Assert.Equal(28, lineBreaker.Current.PositionWrap);
- Assert.False(lineBreaker.Current.Required);
- Assert.False(lineBreaker.MoveNext());
- }
- [Fact]
- public void ForwardTextWithOuterWhitespace()
- {
- var lineBreaker = new LineBreakEnumerator(" Apples Pears Bananas ".AsMemory());
- var positionsF = GetBreaks(lineBreaker);
- Assert.Equal(1, positionsF[0].PositionWrap);
- Assert.Equal(0, positionsF[0].PositionMeasure);
- Assert.Equal(8, positionsF[1].PositionWrap);
- Assert.Equal(7, positionsF[1].PositionMeasure);
- Assert.Equal(14, positionsF[2].PositionWrap);
- Assert.Equal(13, positionsF[2].PositionMeasure);
- Assert.Equal(24, positionsF[3].PositionWrap);
- Assert.Equal(21, positionsF[3].PositionMeasure);
- }
- private static List<LineBreak> GetBreaks(LineBreakEnumerator lineBreaker)
- {
- var breaks = new List<LineBreak>();
- while (lineBreaker.MoveNext())
- {
- breaks.Add(lineBreaker.Current);
- }
- return breaks;
- }
- [Fact]
- public void ForwardTest()
- {
- var lineBreaker = new LineBreakEnumerator("Apples Pears Bananas".AsMemory());
- var positionsF = GetBreaks(lineBreaker);
- Assert.Equal(7, positionsF[0].PositionWrap);
- Assert.Equal(6, positionsF[0].PositionMeasure);
- Assert.Equal(13, positionsF[1].PositionWrap);
- Assert.Equal(12, positionsF[1].PositionMeasure);
- Assert.Equal(20, positionsF[2].PositionWrap);
- Assert.Equal(20, positionsF[2].PositionMeasure);
- }
- [Theory(Skip = "Only run when the Unicode spec changes.")]
- [ClassData(typeof(LineBreakTestDataGenerator))]
- public void ShouldFindBreaks(int lineNumber, int[] codePoints, int[] breakPoints)
- {
- var text = string.Join(null, codePoints.Select(char.ConvertFromUtf32));
- var lineBreaker = new LineBreakEnumerator(text.AsMemory());
- var foundBreaks = new List<int>();
-
- while (lineBreaker.MoveNext())
- {
- foundBreaks.Add(lineBreaker.Current.PositionWrap);
- }
-
- // Check the same
- var pass = true;
- if (foundBreaks.Count != breakPoints.Length)
- {
- pass = false;
- }
- else
- {
- for (var i = 0; i < foundBreaks.Count; i++)
- {
- if (foundBreaks[i] != breakPoints[i])
- {
- pass = false;
- }
- }
- }
- if (!pass)
- {
- _outputHelper.WriteLine($"Failed test on line {lineNumber}");
- _outputHelper.WriteLine("");
- _outputHelper.WriteLine($" Code Points: {string.Join(" ", codePoints)}");
- _outputHelper.WriteLine($"Expected Breaks: {string.Join(" ", breakPoints)}");
- _outputHelper.WriteLine($" Actual Breaks: {string.Join(" ", foundBreaks)}");
- _outputHelper.WriteLine($" Text: {text}");
- _outputHelper.WriteLine($" Char Props: {string.Join(" ", codePoints.Select(x => new Codepoint((uint)x).LineBreakClass))}");
- _outputHelper.WriteLine("");
- }
-
- Assert.True(pass);
- }
- private class LineBreakTestDataGenerator : IEnumerable<object[]>
- {
- private readonly List<object[]> _testData;
- public LineBreakTestDataGenerator()
- {
- _testData = GenerateTestData();
- }
- public IEnumerator<object[]> GetEnumerator()
- {
- return _testData.GetEnumerator();
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- private static List<object[]> GenerateTestData()
- {
- // Process each line
- var tests = new List<object[]>();
- // Read the test file
- var url = Path.Combine(UnicodeDataGenerator.Ucd, "auxiliary/LineBreakTest.txt");
- using (var client = new HttpClient())
- using (var result = client.GetAsync(url).GetAwaiter().GetResult())
- {
- if (!result.IsSuccessStatusCode)
- {
- return tests;
- }
- using (var stream = result.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
- using (var reader = new StreamReader(stream))
- {
- var lineNumber = 1;
- while (!reader.EndOfStream)
- {
- var line = reader.ReadLine();
- if (line is null)
- {
- break;
- }
- // Get the line, remove comments
- line = line.Split('#')[0].Trim();
- // Ignore blank/comment only lines
- if (string.IsNullOrWhiteSpace(line))
- {
- lineNumber++;
- continue;
- }
- var codePoints = new List<int>();
- var breakPoints = new List<int>();
- // Parse the test
- var p = 0;
- while (p < line.Length)
- {
- // Ignore white space
- if (char.IsWhiteSpace(line[p]))
- {
- p++;
- continue;
- }
- if (line[p] == '×')
- {
- p++;
- continue;
- }
- if (line[p] == '÷')
- {
- breakPoints.Add(codePoints.Select(x=> x > ushort.MaxValue ? 2 : 1).Sum());
- p++;
- continue;
- }
- var codePointPos = p;
- while (p < line.Length && IsHexDigit(line[p]))
- {
- p++;
- }
- var codePointStr = line.Substring(codePointPos, p - codePointPos);
- var codePoint = Convert.ToInt32(codePointStr, 16);
- codePoints.Add(codePoint);
- }
- tests.Add(new object[] { lineNumber, codePoints.ToArray(), breakPoints.ToArray() });
- lineNumber++;
- }
- }
- }
- return tests;
- }
- private static bool IsHexDigit(char ch)
- {
- return char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
- }
- }
- }
- }
|