public static bool Run() { Console.WriteLine("Text Block Load Test"); Console.WriteLine("--------------------"); Console.WriteLine(); string typefaceName = "Arial"; float Scale = 1.5f; var styleSmall = new Style() { FontFamily = typefaceName, FontSize = 12 * Scale }; var styleScript = new Style() { FontFamily = "Segoe Script", FontSize = 18 * Scale }; var styleHeading = new Style() { FontFamily = typefaceName, FontSize = 24 * Scale, FontWeight = 700 }; var styleNormal = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, LineHeight = 1.0f }; var styleBold = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, FontWeight = 700 }; var styleUnderline = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, Underline = UnderlineStyle.Gapped }; var styleStrike = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, StrikeThrough = StrikeThroughStyle.Solid }; var styleSubScript = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, FontVariant = FontVariant.SubScript }; var styleSuperScript = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale, FontVariant = FontVariant.SuperScript }; var styleItalic = new Style() { FontFamily = typefaceName, FontItalic = true, FontSize = 18 * Scale }; var styleBoldLarge = new Style() { FontFamily = typefaceName, FontSize = 28 * Scale, FontWeight = 700 }; var styleRed = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale /*, TextColor = new SKColor(0xFFFF0000) */ }; var styleBlue = new Style() { FontFamily = typefaceName, FontSize = 18 * Scale /*, TextColor = new SKColor(0xFF0000FF) */ }; var tr = new TestResults(); var tb = new TextBlock(); for (int i = 0; i < 1000; i++) { tr.EnterTest(); tb.Clear(); tb.MaxWidth = 1000; tb.AddText("Welcome to RichTextKit!\n", styleHeading); tb.AddText("\nRichTextKit is a rich text layout, rendering and measurement library for SkiaSharp.\n\nIt supports normal, ", styleNormal); tb.AddText("bold", styleBold); tb.AddText(", ", styleNormal); tb.AddText("italic", styleItalic); tb.AddText(", ", styleNormal); tb.AddText("underline", styleUnderline); tb.AddText(" (including ", styleNormal); tb.AddText("gaps over descenders", styleUnderline); tb.AddText("), ", styleNormal); tb.AddText("strikethrough", styleStrike); tb.AddText(", superscript (E=mc", styleNormal); tb.AddText("2", styleSuperScript); tb.AddText("), subscript (H", styleNormal); tb.AddText("2", styleSubScript); tb.AddText("O), ", styleNormal); tb.AddText("colored ", styleRed); tb.AddText("text", styleBlue); tb.AddText(" and ", styleNormal); tb.AddText("mixed ", styleNormal); tb.AddText("sizes", styleSmall); tb.AddText(" and ", styleNormal); tb.AddText("fonts", styleScript); tb.AddText(".\n\n", styleNormal); tb.AddText("Font fallback means emojis work: 🌐 🍪 🍕 🚀 and ", styleNormal); tb.AddText("text shaping and bi-directional text support means complex scripts and languages like Arabic: مرحبا بالعالم, Japanese: ハローワールド, Chinese: 世界您好 and Hindi: हैलो वर्ल्ड are rendered correctly!\n\n", styleNormal); tb.AddText("RichTextKit also supports left/center/right text alignment, word wrapping, truncation with ellipsis place-holder, text measurement, hit testing, painting a selection range, caret position & shape helpers.", styleNormal); tb.Layout(); tr.LeaveTest(); tr.TestPassed(true); } tr.Dump(); return(tr.AllPassed); }
public static bool Run() { Console.WriteLine("Bidi Character Tests"); Console.WriteLine("--------------------"); Console.WriteLine(); // Read the test file var location = System.IO.Path.GetDirectoryName(typeof(Program).Assembly.Location); var lines = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, "BidiCharacterTest.txt")); // Parse lines var tests = new List <Test>(); for (int lineNumber = 1; lineNumber < lines.Length + 1; lineNumber++) { // Get the line, remove comments var line = lines[lineNumber - 1].Split('#')[0].Trim(); // Ignore blank/comment only lines if (string.IsNullOrWhiteSpace(line)) { continue; } // Split into fields var fields = line.Split(';'); var test = new Test(); test.LineNumber = lineNumber; // Parse field 0 - code points test.CodePoints = fields[0].Split(' ').Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).Select(x => Convert.ToInt32(x, 16)).ToArray(); // Parse field 1 - paragraph level test.ParagraphLevel = sbyte.Parse(fields[1]); // Parse field 2 - resolved paragraph level test.ResolvedParagraphLevel = sbyte.Parse(fields[2]); // Parse field 3 - resolved levels test.ResolvedLevels = fields[3].Split(' ').Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).Select(x => x == "x" ? (sbyte)-1 : Convert.ToSByte(x)).ToArray(); // Parse field 4 - resolved levels test.ResolvedOrder = fields[4].Split(' ').Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).Select(x => Convert.ToInt32(x)).ToArray(); tests.Add(test); } Console.WriteLine($"Test data loaded: {tests.Count} test cases"); var bidi = new Bidi(); var bidiData = new BidiData(); // Run tests... var tr = new TestResults(); for (int testNumber = 0; testNumber < tests.Count; testNumber++) { var t = tests[testNumber]; // Arrange bidiData.Init(new Slice <int>(t.CodePoints), t.ParagraphLevel); // Act tr.EnterTest(); for (int i = 0; i < 10; i++) { bidi.Process(bidiData); } tr.LeaveTest(); var resultLevels = bidi.ResolvedLevels; int resultParagraphLevel = bidi.ResolvedParagraphEmbeddingLevel; // Assert bool passed = true; if (t.ResolvedParagraphLevel != resultParagraphLevel) { passed = false; } for (int i = 0; i < t.ResolvedLevels.Length; i++) { if (t.ResolvedLevels[i] == -1) { continue; } if (t.ResolvedLevels[i] != resultLevels[i]) { passed = false; break; } } /* * if (!passed) * { * Console.WriteLine($"Failed line {t.LineNumber}"); * Console.WriteLine(); * Console.WriteLine($" Code Points: {string.Join(" ", t.CodePoints.Select(x => x.ToString("X4")))}"); * Console.WriteLine($" Pair Bracket Types: {string.Join(" ", bidiData.PairedBracketTypes.Select(x => " " + x.ToString()))}"); * Console.WriteLine($" Pair Bracket Values: {string.Join(" ", bidiData.PairedBracketValues.Select(x => x.ToString("X4")))}"); * Console.WriteLine($" Embed Level: {t.ParagraphLevel}"); * Console.WriteLine($" Expected Embed Level: {t.ResolvedParagraphLevel}"); * Console.WriteLine($" Actual Embed Level: {resultParagraphLevel}"); * Console.WriteLine($" Directionality: {string.Join(" ", bidiData.Types)}"); * Console.WriteLine($" Expected Levels: {string.Join(" ", t.ResolvedLevels)}"); * Console.WriteLine($" Actual Levels: {string.Join(" ", resultLevels)}"); * Console.WriteLine(); * return false; * } */ // Record it tr.TestPassed(passed); } tr.Dump(); return(tr.AllPassed); }
public static bool Run() { Console.WriteLine("Bidi Class Tests"); Console.WriteLine("----------------"); Console.WriteLine(); // Read the test file var location = System.IO.Path.GetDirectoryName(typeof(Program).Assembly.Location); var lines = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, "BidiTest.txt")); var bidi = new Bidi(); List <Test> tests = new List <Test>(); // Process each line int[] levels = null; for (int lineNumber = 1; lineNumber < lines.Length + 1; lineNumber++) { // Get the line, remove comments var line = lines[lineNumber - 1].Split('#')[0].Trim(); // Ignore blank/comment only lines if (string.IsNullOrWhiteSpace(line)) { continue; } // Directive? if (line.StartsWith("@")) { if (line.StartsWith("@Levels:")) { levels = line.Substring(8).Trim().Split(' ').Where(x => x.Length > 0).Select(x => { if (x == "x") { return(-1); } else { return(int.Parse(x)); } }).ToArray(); } continue; } // Split data line var parts = line.Split(';'); System.Diagnostics.Debug.Assert(parts.Length == 2); // Get the directions var directions = parts[0].Split(' ').Select(x => DirectionalityFromName(x)).ToArray(); // Get the bit set var bitset = Convert.ToInt32(parts[1].Trim(), 16); var pairTypes = Enumerable.Repeat(PairedBracketType.n, directions.Length).ToArray(); var pairValues = Enumerable.Repeat(0, directions.Length).ToArray(); for (int bit = 1; bit < 8; bit <<= 1) { if ((bitset & bit) == 0) { continue; } sbyte paragraphEmbeddingLevel; switch (bit) { case 1: paragraphEmbeddingLevel = 2; // Auto break; case 2: paragraphEmbeddingLevel = 0; // LTR break; case 4: paragraphEmbeddingLevel = 1; // RTL break; default: throw new NotImplementedException(); } tests.Add(new Test() { Types = new Slice <Directionality>(directions), ParagraphEmbeddingLevel = paragraphEmbeddingLevel, ExpectedLevels = levels, LineNumber = lineNumber, }); } } Console.WriteLine($"Test data loaded: {tests.Count} test cases"); var tr = new TestResults(); #if FOR_PROFILING for (int repeat = 0; repeat < 50; repeat++) #endif for (int testNumber = 0; testNumber < tests.Count; testNumber++) { var t = tests[testNumber]; // Run the algorithm... Slice <sbyte> resultLevels; tr.EnterTest(); bidi.Process(t.Types, Slice <PairedBracketType> .Empty, Slice <int> .Empty, t.ParagraphEmbeddingLevel, false, null, null, null); tr.LeaveTest(); resultLevels = bidi.ResolvedLevels; // Check the results match bool pass = true; if (resultLevels.Length == t.ExpectedLevels.Length) { for (int i = 0; i < t.ExpectedLevels.Length; i++) { if (t.ExpectedLevels[i] == -1) { continue; } if (resultLevels[i] != t.ExpectedLevels[i]) { pass = false; break; } } } else { pass = false; } tr.TestPassed(pass); if (pass) { // Console.WriteLine($"Passed line {t.LineNumber} {t.ParagraphEmbeddingLevel}"); } else { Console.WriteLine($"Failed line {t.LineNumber}"); Console.WriteLine(); Console.WriteLine($" Data: {string.Join(" ", t.Types)}"); Console.WriteLine($" Embed Level: {t.ParagraphEmbeddingLevel}"); Console.WriteLine($" Expected: {string.Join(" ", t.ExpectedLevels)}"); Console.WriteLine($" Actual: {string.Join(" ", resultLevels)}"); Console.WriteLine(); return(false); } } tr.Dump(); return(tr.AllPassed); }
public static bool Run() { Console.WriteLine("Line Breaker Tests"); Console.WriteLine("------------------"); Console.WriteLine(); // Read the test file var location = System.IO.Path.GetDirectoryName(typeof(LineBreakTest).Assembly.Location); var lines = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, "LineBreakTest.txt")); // Process each line var tests = new List <Test>(); for (int lineNumber = 1; lineNumber < lines.Length + 1; lineNumber++) { // Ignore deliberately skipped test? if (_skipLines.Contains(lineNumber - 1)) { continue; } // Get the line, remove comments var line = lines[lineNumber - 1].Split('#')[0].Trim(); // Ignore blank/comment only lines if (string.IsNullOrWhiteSpace(line)) { 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.Count); p++; continue; } int 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); } // Create test var test = new Test() { LineNumber = lineNumber, CodePoints = codePoints.ToArray(), BreakPoints = breakPoints.ToArray(), }; tests.Add(test); } var lineBreaker = new LineBreaker(); var tr = new TestResults(); var foundBreaks = new List <int>(); foundBreaks.Capacity = 100; for (int testNumber = 0; testNumber < tests.Count; testNumber++) { var t = tests[testNumber]; foundBreaks.Clear(); // Run the line breaker and build a list of break points tr.EnterTest(); lineBreaker.Reset(new Slice <int>(t.CodePoints)); while (lineBreaker.NextBreak(out var b)) { foundBreaks.Add(b.PositionWrap); } tr.LeaveTest(); // Check the same bool pass = true; if (foundBreaks.Count != t.BreakPoints.Length) { pass = false; } else { for (int i = 0; i < foundBreaks.Count; i++) { if (foundBreaks[i] != t.BreakPoints[i]) { pass = false; } } } if (!pass) { Console.WriteLine($"Failed test on line {t.LineNumber}"); Console.WriteLine(); Console.WriteLine($" Code Points: {string.Join(" ", t.CodePoints)}"); Console.WriteLine($"Expected Breaks: {string.Join(" ", t.BreakPoints)}"); Console.WriteLine($" Actual Breaks: {string.Join(" ", foundBreaks)}"); Console.WriteLine($" Char Props: {string.Join(" ", t.CodePoints.Select(x => UnicodeClasses.LineBreakClass(x)))}"); Console.WriteLine(); return(false); } // Record it tr.TestPassed(pass); } tr.Dump(); return(tr.AllPassed); }