Moved over test cases from GuiKit

This commit is contained in:
Brad Robinson 2019-08-01 19:20:36 +10:00
Родитель 751d460689
Коммит 370c919eba
6 изменённых файлов: 6918 добавлений и 1 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
namespace Topten.RichText.Test
{
public class LineBreakTests
{
[Fact]
public void BasicLatinTest()
{
var lineBreaker = new LineBreaker();
lineBreaker.Reset("Hello World\r\nThis is a test.");
LineBreak b;
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(6, b.PositionWrap);
Assert.False(b.Required);
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(13, b.PositionWrap);
Assert.True(b.Required);
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(18, b.PositionWrap);
Assert.False(b.Required);
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(21, b.PositionWrap);
Assert.False(b.Required);
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(23, b.PositionWrap);
Assert.False(b.Required);
Assert.True(lineBreaker.NextBreak(out b));
Assert.Equal(28, b.PositionWrap);
Assert.False(b.Required);
Assert.False(lineBreaker.NextBreak(out b));
}
[Fact]
void ForwardTextWithOuterWhitespace()
{
var lineBreaker = new LineBreaker();
lineBreaker.Reset(" Apples Pears Bananas ");
var positionsF = lineBreaker.GetBreaks().ToList();
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);
}
[Fact]
void ForwardTest()
{
var lineBreaker = new LineBreaker();
lineBreaker.Reset("Apples Pears Bananas");
var positionsF = lineBreaker.GetBreaks().ToList();
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);
}
[Fact]
public void Test()
{
// Read the test file
var location = System.IO.Path.GetDirectoryName(typeof(LineBreakTests).Assembly.Location);
var lines = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, "LineBreakTest.txt"));
// Process each line
int lineNumber = 0;
foreach (var line in lines)
{
// Ignore deliberately skipped test?
if (_skipLines.Contains(lineNumber))
continue;
lineNumber++;
// Split the line
var parts = line.Split("#");
var test = parts[0].Trim();
// Ignore blank/comment only lines
if (string.IsNullOrWhiteSpace(test))
continue;
// Parse the test
var p = 0;
List<int> codePoints = new List<int>();
List<int> breakPoints = new List<int>();
while (p < test.Length)
{
// Ignore white space
if (char.IsWhiteSpace(test[p]))
{
p++;
continue;
}
if (test[p] == '×')
{
p++;
continue;
}
if (test[p] == '÷')
{
breakPoints.Add(codePoints.Count);
p++;
continue;
}
int codePointPos = p;
while (p < test.Length && IsHexDigit(test[p]))
p++;
var codePointStr = test.Substring(codePointPos, p - codePointPos);
var codePoint = Convert.ToInt32(codePointStr, 16);
codePoints.Add(codePoint);
}
// Run the line breaker and build a list of break points
List<int> foundBreaks = new List<int>();
var lineBreaker = new LineBreaker();
lineBreaker.Reset(new Slice<int>(codePoints.ToArray()));
while (lineBreaker.NextBreak(out var b))
{
foundBreaks.Add(b.PositionWrap);
}
// Check the same
Assert.Equal(breakPoints, foundBreaks);
}
}
static bool IsHexDigit(char ch)
{
return char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
}
// these tests are weird, possibly incorrect or just tailored differently. we skip them.
static HashSet<int> _skipLines = new HashSet<int>()
{
812, 814, 848, 850, 864, 866, 900, 902, 956, 958, 1068, 1070, 1072, 1074, 1224, 1226,
1228, 1230, 1760, 1762, 2932, 2934, 4100, 4101, 4102, 4103, 4340, 4342, 4496, 4498, 4568, 4570,
4704, 4706, 4707, 4708, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4719, 4722, 4723, 4726, 4727,
4730, 4731, 4734, 4735, 4736, 4738, 4739, 4742, 4743, 4746, 4747, 4748, 4750, 4751, 4752, 4754,
4755, 4756, 4758, 4759, 4760, 4762, 4763, 4764, 4766, 4767, 4768, 4770, 4771, 4772, 4774, 4775,
4778, 4779, 4780, 4782, 4783, 4784, 4786, 4787, 4788, 4790, 4791, 4794, 4795, 4798, 4799, 4800,
4802, 4803, 4804, 4806, 4807, 4808, 4810, 4811, 4812, 4814, 4815, 4816, 4818, 4819, 4820, 4822,
4823, 4826, 4827, 4830, 4831, 4834, 4835, 4838, 4839, 4840, 4842, 4843, 4844, 4846, 4847, 4848,
4850, 4851, 4852, 4854, 4855, 4856, 4858, 4859, 4960, 4962, 5036, 5038, 6126, 6135, 6140, 6225,
6226, 6227, 6228, 6229, 6230, 6232, 6233, 6234, 6235, 6236, 6332,
};
}
}

Просмотреть файл

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="SkiaSharp" Version="1.68.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Topten.RichText\Topten.RichText.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="LineBreakTest.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
// Ported from: https://github.com/foliojs/unicode-trie
namespace Topten.RichText.Test
{
public class TrieBuilderTest
{
[Fact]
public void Set()
{
var trie = new UnicodeTrieBuilder(10, 666);
trie.Set(0x4567, 99);
Assert.Equal(10u, trie.Get(0x4566));
Assert.Equal(99u, trie.Get(0x4567));
Assert.Equal(666u, trie.Get(-1));
Assert.Equal(666u, trie.Get(0x110000));
}
[Fact]
public void SetCompacted()
{
var builder = new UnicodeTrieBuilder(10, 666);
builder.Set(0x4567, 99);
var trie = builder.Freeze();
Assert.Equal(10u, trie.Get(0x4566));
Assert.Equal(99u, trie.Get(0x4567));
Assert.Equal(666u, trie.Get(-1));
Assert.Equal(666u, trie.Get(0x110000));
}
[Fact]
public void SetRange()
{
var trie = new UnicodeTrieBuilder(10, 666);
trie.SetRange(13, 6666, 7788, false);
trie.SetRange(6000, 7000, 9900, true);
Assert.Equal(10u, trie.Get(12));
Assert.Equal(7788u, trie.Get(13));
Assert.Equal(7788u, trie.Get(5999));
Assert.Equal(9900u, trie.Get(6000));
Assert.Equal(9900u, trie.Get(7000));
Assert.Equal(10u, trie.Get(7001));
Assert.Equal(666u, trie.Get(0x110000));
}
[Fact]
public void SetRangeCompacted()
{
var builder = new UnicodeTrieBuilder(10, 666);
builder.SetRange(13, 6666, 7788, false);
builder.SetRange(6000, 7000, 9900, true);
var trie = builder.Freeze();
Assert.Equal(10u, trie.Get(12));
Assert.Equal(7788u, trie.Get(13));
Assert.Equal(7788u, trie.Get(5999));
Assert.Equal(9900u, trie.Get(6000));
Assert.Equal(9900u, trie.Get(7000));
Assert.Equal(10u, trie.Get(7001));
Assert.Equal(666u, trie.Get(0x110000));
}
[Fact]
public void SetRangeSerialized()
{
var builder = new UnicodeTrieBuilder(10, 666);
builder.SetRange(13, 6666, 7788, false);
builder.SetRange(6000, 7000, 9900, true);
var data = builder.ToBuffer();
var trie = new UnicodeTrie(data);
Assert.Equal(10u, trie.Get(12));
Assert.Equal(7788u, trie.Get(13));
Assert.Equal(7788u, trie.Get(5999));
Assert.Equal(9900u, trie.Get(6000));
Assert.Equal(9900u, trie.Get(7000));
Assert.Equal(10u, trie.Get(7001));
Assert.Equal(666u, trie.Get(0x110000));
}
public class TestRange
{
public TestRange(int start, int end, uint value, bool overwrite)
{
this.start = start;
this.end = end;
this.value = value;
this.overwrite = overwrite;
}
public int start;
public int end;
public uint value;
public bool overwrite;
}
public class CheckValue
{
public CheckValue(int codePoint, uint value)
{
this.codePoint = codePoint;
this.value = value;
}
public int codePoint;
public uint value;
}
static TestRange[] TestRanges1 = new TestRange[] {
new TestRange(0, 0, 0, false),
new TestRange(0, 0x40, 0, false),
new TestRange(0x40, 0xe7, 0x1234, false),
new TestRange(0xe7, 0x3400, 0, false),
new TestRange(0x3400, 0x9fa6, 0x6162, false),
new TestRange(0x9fa6, 0xda9e, 0x3132, false),
new TestRange(0xdada, 0xeeee, 0x87ff, false),
new TestRange(0xeeee, 0x11111, 1, false),
new TestRange(0x11111, 0x44444, 0x6162, false),
new TestRange(0x44444, 0x60003, 0, false),
new TestRange(0xf0003, 0xf0004, 0xf, false),
new TestRange(0xf0004, 0xf0006, 0x10, false),
new TestRange(0xf0006, 0xf0007, 0x11, false),
new TestRange(0xf0007, 0xf0040, 0x12, false),
new TestRange(0xf0040, 0x110000, 0, false)
};
static CheckValue[] CheckValues1 = new CheckValue[] {
new CheckValue(0, 0 ),
new CheckValue(0x40, 0 ),
new CheckValue(0xe7, 0x1234 ),
new CheckValue(0x3400, 0 ),
new CheckValue(0x9fa6, 0x6162 ),
new CheckValue(0xda9e, 0x3132 ),
new CheckValue(0xdada, 0 ),
new CheckValue(0xeeee, 0x87ff ),
new CheckValue(0x11111, 1 ),
new CheckValue(0x44444, 0x6162 ),
new CheckValue(0xf0003, 0 ),
new CheckValue(0xf0004, 0xf ),
new CheckValue(0xf0006, 0x10 ),
new CheckValue(0xf0007, 0x11 ),
new CheckValue(0xf0040, 0x12 ),
new CheckValue(0x110000, 0 ),
};
static TestRange[] TestRanges2 = new TestRange[] {
new TestRange(0, 0, 0, false),
new TestRange(0x21, 0x7f, 0x5555, true),
new TestRange(0x2f800, 0x2fedc, 0x7a, true),
new TestRange(0x72, 0xdd, 3, true),
new TestRange(0xdd, 0xde, 4, false),
new TestRange(0x201, 0x240, 6, true), // 3 consecutive blocks with the same pattern but
new TestRange(0x241, 0x280, 6, true), // discontiguous value ranges, testing utrie2_enum()
new TestRange(0x281, 0x2c0, 6, true),
new TestRange(0x2f987, 0x2fa98, 5, true),
new TestRange(0x2f777, 0x2f883, 0, true),
new TestRange(0x2f900, 0x2ffaa, 1, false),
new TestRange(0x2ffaa, 0x2ffab, 2, true),
new TestRange(0x2ffbb, 0x2ffc0, 7, true),
};
static CheckValue[] CheckValues2 = new CheckValue[] {
new CheckValue(0, 0 ),
new CheckValue(0x21, 0 ),
new CheckValue(0x72, 0x5555 ),
new CheckValue(0xdd, 3 ),
new CheckValue(0xde, 4 ),
new CheckValue(0x201, 0 ),
new CheckValue(0x240, 6 ),
new CheckValue(0x241, 0 ),
new CheckValue(0x280, 6 ),
new CheckValue(0x281, 0 ),
new CheckValue(0x2c0, 6 ),
new CheckValue(0x2f883, 0 ),
new CheckValue(0x2f987, 0x7a ),
new CheckValue(0x2fa98, 5 ),
new CheckValue(0x2fedc, 0x7a ),
new CheckValue(0x2ffaa, 1 ),
new CheckValue(0x2ffab, 2 ),
new CheckValue(0x2ffbb, 0 ),
new CheckValue(0x2ffc0, 7 ),
new CheckValue(0x110000, 0 ),
};
static TestRange[] TestRanges3 = new TestRange[] {
new TestRange(0, 0, 9, false), // non-zero initial value.
new TestRange(0x31, 0xa4, 1, false),
new TestRange(0x3400, 0x6789, 2, false),
new TestRange(0x8000, 0x89ab, 9, true),
new TestRange(0x9000, 0xa000, 4, true),
new TestRange(0xabcd, 0xbcde, 3, true),
new TestRange(0x55555, 0x110000, 6, true), // highStart<U+ffff with non-initialValue
new TestRange(0xcccc, 0x55555, 6, true),
};
static CheckValue[] CheckValues3 = new CheckValue[] {
new CheckValue(0, 9 ), // non-zero initialValue
new CheckValue(0x31, 9 ),
new CheckValue(0xa4, 1 ),
new CheckValue(0x3400, 9 ),
new CheckValue(0x6789, 2 ),
new CheckValue(0x9000, 9 ),
new CheckValue(0xa000, 4 ),
new CheckValue(0xabcd, 9 ),
new CheckValue(0xbcde, 3 ),
new CheckValue(0xcccc, 9 ),
new CheckValue(0x110000, 6 ),
};
static TestRange[] TestRanges4 = new TestRange[] {
new TestRange(0, 0, 3, false), // Only the element with the initial value.
};
static CheckValue[] CheckValues4 = new CheckValue[] {
new CheckValue(0, 3 ),
new CheckValue(0x110000, 3 ),
};
static TestRange[] TestRanges5 = new TestRange[] {
new TestRange(0, 0, 3, false), // Initial value = 3
new TestRange(0, 0x110000, 5, true)
};
static CheckValue[] CheckValues5 = new CheckValue[] {
new CheckValue(0, 3 ),
new CheckValue(0x110000, 5),
};
public static IEnumerable<object[]> TestData()
{
yield return new object[] { TestRanges1, CheckValues1 };
yield return new object[] { TestRanges2, CheckValues2 };
yield return new object[] { TestRanges3, CheckValues3 };
yield return new object[] { TestRanges4, CheckValues4 };
yield return new object[] { TestRanges5, CheckValues5 };
}
[Theory]
[MemberData(nameof(TestData))]
public void RunRangeChecks(TestRange[] testRanges, CheckValue[] checkValues)
{
uint initialValue = testRanges[0].value;
uint errorValue = 0x0bad;
var builder = new UnicodeTrieBuilder(initialValue, errorValue);
for (int i = 1; i < testRanges.Length; i++)
{
var r = testRanges[i];
builder.SetRange(r.start, r.end - 1, r.value, r.overwrite);
}
var frozen = builder.Freeze();
int cp = 0;
for (int i=0; i<checkValues.Length; i++)
{
var v = checkValues[i];
for (; cp < v.codePoint; cp++)
{
Assert.Equal(v.value, builder.Get(cp));
Assert.Equal(v.value, frozen.Get(cp));
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
namespace Topten.RichText.Test
{
public class Utf32BufferTests
{
const string mixedString = "This\r\na\r\nstring\n🌐 🍪 🍕 🚀\n يتكلّم \n हालाँकि प्रचलित रूप पूज 緳 踥踕";
[Fact]
public void Map32to16Test()
{
// Arrange
var buf = new Utf32Buffer();
// Act
buf.Add(mixedString);
// Assert
for (int i32 = 0; i32 < buf.Length; i32++)
{
var i16 = buf.Utf32OffsetToUtf16Offset(i32);
var i32b = buf.Utf16OffsetToUtf32Offset(i16);
Assert.Equal(i32, i32b);
}
}
[Fact]
public void Map16to32Test()
{
// Arrange
var buf = new Utf32Buffer();
// Act
buf.Add(mixedString);
// Assert
for (int i = 0; i < mixedString.Length; i++)
{
char ch = mixedString[i];
var ch32 = buf[buf.Utf16OffsetToUtf32Offset(i)];
if (ch >= 0xD800 && ch <= 0xDFFF)
{
var chL = mixedString[i+1];
var ch32actual = 0x10000 | ((ch - 0xD800) << 10) | (chL - 0xDC00);
Assert.Equal(ch32, ch32actual);
i++;
}
else if (ch == '\r' && mixedString[i+1] == '\n')
{
Assert.Equal('\n', ch32);
i++;
}
else
{
Assert.Equal(ch, ch32);
}
}
}
[Fact]
public void MapSurrogateToBase()
{
// Arrange
var buf = new Utf32Buffer();
// Act
buf.Add(mixedString);
// Assert
for (int i = 0; i < mixedString.Length; i++)
{
char ch = mixedString[i];
if ((ch >= 0xDC00 && ch <= 0xDFFF) || (ch == '\n' && mixedString[i-1] == '\r'))
{
int prior = buf.Utf16OffsetToUtf32Offset(i - 1);
int current = buf.Utf16OffsetToUtf32Offset(i);
Assert.Equal(prior, current);
}
}
}
[Fact]
public void ConvertToUtf16()
{
// Arrange
var buf = new Utf32Buffer();
// Act
buf.Add(mixedString);
var str2 = Utf32Utils.FromUtf32(buf.AsSlice());
// Assert
Assert.Equal(mixedString.Replace("\r", ""), str2);
}
}
}

Просмотреть файл

@ -7,7 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Topten.RichText", "Topten.R
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox\Sandbox.csproj", "{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SandboxDriver", "SandboxDriver\SandboxDriver.csproj", "{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SandboxDriver", "SandboxDriver\SandboxDriver.csproj", "{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Topten.RichText.Test", "Topten.RichText.Test\Topten.RichText.Test.csproj", "{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -27,6 +29,10 @@ Global
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Release|Any CPU.Build.0 = Release|Any CPU
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE