|
| 1 | +// (c) 2022 and onwards The vChewing Project (LGPL v3.0 License or later). |
| 2 | +// ==================== |
| 3 | +// This code is released under the SPDX-License-Identifier: `LGPL-3.0-or-later`. |
| 4 | + |
| 5 | +using System; |
| 6 | +using System.Collections.Generic; |
| 7 | +using System.Linq; |
| 8 | + |
| 9 | +using NUnit.Framework; |
| 10 | + |
| 11 | +namespace Tekkon.Tests { |
| 12 | + /// <summary> |
| 13 | + /// 資料驅動測試案例的輔助類別。 |
| 14 | + /// </summary> |
| 15 | + public class SubTestCase { |
| 16 | + public MandarinParser Parser { get; } |
| 17 | + public string Typing { get; } |
| 18 | + public string Expected { get; } |
| 19 | + |
| 20 | + public SubTestCase(MandarinParser parser, string typing, string expected) { |
| 21 | + // 略過以反引號標記的測試案例 |
| 22 | + if (typing.StartsWith("`")) { |
| 23 | + Parser = parser; |
| 24 | + Typing = ""; |
| 25 | + Expected = ""; |
| 26 | + return; |
| 27 | + } |
| 28 | + Parser = parser; |
| 29 | + Typing = typing.Replace("_", " "); |
| 30 | + Expected = expected.Replace("_", " "); |
| 31 | + } |
| 32 | + |
| 33 | + public bool Verify() { |
| 34 | + if (string.IsNullOrEmpty(Typing)) return true; |
| 35 | + |
| 36 | + var composer = new Composer(arrange: Parser); |
| 37 | + string strResult = composer.CnvSequence(Typing); |
| 38 | + if (strResult == Expected) return true; |
| 39 | + |
| 40 | + string parserTag = Parser.NameTag(); |
| 41 | + string strError = $"MISMATCH ({parserTag}): \"{Typing}\" -> \"{strResult}\" != \"{Expected}\""; |
| 42 | + Console.WriteLine(strError); |
| 43 | + return false; |
| 44 | + } |
| 45 | + } |
| 46 | + |
| 47 | + /// <summary> |
| 48 | + /// 靜態鍵盤排列測試(例如:大千排列)。 |
| 49 | + /// </summary> |
| 50 | + public class TekkonTestsKeyboardArrangementsStatic { |
| 51 | + private void CheckEq(ref int counter, ref Composer composer, string strGivenSeq, string strExpected) { |
| 52 | + string strResult = composer.CnvSequence(strGivenSeq); |
| 53 | + if (strResult == strExpected) return; |
| 54 | + |
| 55 | + string parserTag = composer.Parser.NameTag(); |
| 56 | + string strError = $"MISMATCH ({parserTag}): \"{strGivenSeq}\" -> \"{strResult}\" != \"{strExpected}\""; |
| 57 | + Console.WriteLine(strError); |
| 58 | + counter++; |
| 59 | + } |
| 60 | + |
| 61 | + [Test] |
| 62 | + public void TestQwertyDachenKeys() { |
| 63 | + // 測試大千傳統排列(QWERTY) |
| 64 | + var c = new Composer(arrange: MandarinParser.OfDachen); |
| 65 | + int counter = 0; |
| 66 | + CheckEq(ref counter, ref c, " ", " "); |
| 67 | + CheckEq(ref counter, ref c, "18 ", "ㄅㄚ "); |
| 68 | + CheckEq(ref counter, ref c, "m,4", "ㄩㄝˋ"); |
| 69 | + CheckEq(ref counter, ref c, "5j/ ", "ㄓㄨㄥ "); |
| 70 | + CheckEq(ref counter, ref c, "fu.", "ㄑㄧㄡ"); |
| 71 | + CheckEq(ref counter, ref c, "g0 ", "ㄕㄢ "); |
| 72 | + CheckEq(ref counter, ref c, "xup6", "ㄌㄧㄣˊ"); |
| 73 | + CheckEq(ref counter, ref c, "xu;6", "ㄌㄧㄤˊ"); |
| 74 | + CheckEq(ref counter, ref c, "z/", "ㄈㄥ"); |
| 75 | + CheckEq(ref counter, ref c, "tjo ", "ㄔㄨㄟ "); |
| 76 | + CheckEq(ref counter, ref c, "284", "ㄉㄚˋ"); |
| 77 | + CheckEq(ref counter, ref c, "2u4", "ㄉㄧˋ"); |
| 78 | + CheckEq(ref counter, ref c, "hl3", "ㄘㄠˇ"); |
| 79 | + CheckEq(ref counter, ref c, "5 ", "ㄓ "); |
| 80 | + CheckEq(ref counter, ref c, "193", "ㄅㄞˇ"); |
| 81 | + Assert.AreEqual(0, counter); |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + /// <summary> |
| 86 | + /// 動態鍵盤排列測試(大千26鍵、倚天26鍵、許氏鍵盤、星光鍵盤、劉氏鍵盤)。 |
| 87 | + /// </summary> |
| 88 | + public class TekkonTestsKeyboardArrangementsDynamic { |
| 89 | + [Test] |
| 90 | + public void TestDynamicKeyLayouts() { |
| 91 | + // 取得所有動態排列 |
| 92 | + var dynamicParsers = MandarinParserExtensions.AllDynamicZhuyinCases.ToList(); |
| 93 | + |
| 94 | + foreach (var (parser, idxRaw) in dynamicParsers.Select((p, i) => (p, i))) { |
| 95 | + var cases = new List<SubTestCase>(); |
| 96 | + Console.WriteLine($" -> [Tekkon] 準備動態鍵盤處理測試..."); |
| 97 | + |
| 98 | + // 解析測試資料 |
| 99 | + var lines = TekkonTestData.DynamicLayoutTable.Split('\n', StringSplitOptions.RemoveEmptyEntries); |
| 100 | + bool isTitleLine = true; |
| 101 | + |
| 102 | + foreach (var line in lines) { |
| 103 | + if (isTitleLine) { |
| 104 | + isTitleLine = false; |
| 105 | + continue; |
| 106 | + } |
| 107 | + |
| 108 | + var cells = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); |
| 109 | + if (cells.Length < 2) continue; |
| 110 | + |
| 111 | + string expected = cells[0]; |
| 112 | + int idx = idxRaw + 1; |
| 113 | + if (idx >= cells.Length) continue; |
| 114 | + |
| 115 | + string typing = cells[idx]; |
| 116 | + var testCase = new SubTestCase(parser, typing, expected); |
| 117 | + cases.Add(testCase); |
| 118 | + } |
| 119 | + |
| 120 | + var startTime = DateTime.Now; |
| 121 | + Console.WriteLine($" -> [Tekkon][({parser.NameTag()})] 開始動態鍵盤處理測試..."); |
| 122 | + |
| 123 | + int failures = cases.Select(testCase => testCase.Verify() ? 0 : 1).Sum(); |
| 124 | + |
| 125 | + Assert.AreEqual(0, failures, |
| 126 | + $"[失敗] {parser.NameTag()} 處理失敗,共 {failures} 個錯誤結果。"); |
| 127 | + |
| 128 | + var elapsed = DateTime.Now - startTime; |
| 129 | + Console.WriteLine($" -> [Tekkon][({parser.NameTag()})] 測試完成,耗時 {elapsed.TotalSeconds:F4} 秒。"); |
| 130 | + } |
| 131 | + } |
| 132 | + } |
| 133 | +} |
0 commit comments