// ================================================================================================ // // MediaWikiTranslatorのテストクラスソース。 // // // Copyright (C) 2012 Honeplus. All rights reserved. // // Honeplus // ================================================================================================ namespace Honememo.Wptscs.Logics { using System; using System.Collections.Generic; using System.IO; using System.Reflection; using NUnit.Framework; using Honememo.Tests; using Honememo.Parsers; using Honememo.Utilities; using Honememo.Wptscs.Models; using Honememo.Wptscs.Parsers; using Honememo.Wptscs.Utilities; using Honememo.Wptscs.Websites; /// /// MediaWikiTranslatorのテストクラスです。 /// [TestFixture] public class MediaWikiTranslatorTest { #region テスト用クラス /// /// MediaWikiTranslatorテスト用のクラスです。 /// public class TestMediaWikiTranslator : MediaWikiTranslator { #region 非公開メソッドテスト用のオーラーライドメソッド /// /// 内部リンクを解析し、変換先言語の記事へのリンクに変換する。 /// /// 変換元リンク。 /// サブページ用の親記事タイトル。 /// 変換済みリンク。 public new IElement ReplaceLink(MediaWikiLink link, string parent) { return base.ReplaceLink(link, parent); } /// /// テンプレートを解析し、変換先言語の記事へのテンプレートに変換する。 /// /// 変換元テンプレート。 /// サブページ用の親記事タイトル。 /// 変換済みテンプレート。 public new IElement ReplaceTemplate(MediaWikiTemplate template, string parent) { return base.ReplaceTemplate(template, parent); } /// /// 指定された見出しに対して、対訳表による変換を行う。 /// /// 見出し。 /// サブページ用の親記事タイトル。 /// 変換後の見出し。 public new IElement ReplaceHeading(MediaWikiHeading heading, string parent) { return base.ReplaceHeading(heading, parent); } #endregion } #endregion #region 定数 /// /// テスト結果が格納されているフォルダパス。 /// private static readonly string resultDir = Path.Combine(MockFactory.TestMediaWikiDir, "result"); #endregion #region 各処理のメソッドテストケース /// /// ReplaceLinkメソッドテストケース。 /// [Test] public void TestReplaceLink() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("ja"); translator.To = mock.GetMediaWiki("en"); translator.To.LinkInterwikiFormat = null; // 見出しの変換パターンを設定 translator.HeadingTable = new TranslationTable(); IDictionary dic = new Dictionary(); dic["en"] = "External links"; dic["ja"] = "外部リンク"; translator.HeadingTable.Add(dic); translator.HeadingTable.From = "ja"; translator.HeadingTable.To = "en"; MediaWikiLink link; // 記事名だけの内部リンクで言語間リンクあり、変換先言語へのリンクとなる // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため link = new MediaWikiLink(); link.Title = "ホワイトナイトツー"; Assert.AreEqual("[[Scaled Composites White Knight Two|ホワイトナイトツー]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 見出しあり link = new MediaWikiLink(); link.Title = "ホワイトナイトツー"; link.Section = "見出し"; Assert.AreEqual("[[Scaled Composites White Knight Two#見出し|ホワイトナイトツー#見出し]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 変換パターンに該当する見出しの場合 link = new MediaWikiLink(); link.Title = "ホワイトナイトツー"; link.Section = "外部リンク"; Assert.AreEqual("[[Scaled Composites White Knight Two#External links|ホワイトナイトツー#外部リンク]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 表示名あり link = new MediaWikiLink(); link.Title = "ホワイトナイトツー"; link.Section = "外部リンク"; link.PipeTexts.Add(new TextElement("母機")); Assert.AreEqual("[[Scaled Composites White Knight Two#External links|母機]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 記事名だけの内部リンクで言語間リンクなし、変換元言語へのリンクとなる translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); translator.To.LinkInterwikiFormat = null; translator.HeadingTable.From = "en"; translator.HeadingTable.To = "ja"; link = new MediaWikiLink(); link.Title = "Exemplum"; Assert.AreEqual("[[:en:Exemplum|Exemplum]]", translator.ReplaceLink(link, "example").ToString()); // 見出しあり link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "Three examples of exempla"; Assert.AreEqual("[[:en:Exemplum#Three examples of exempla|Exemplum#Three examples of exempla]]", translator.ReplaceLink(link, "example").ToString()); // 変換パターンに該当する見出しの場合 link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "External links"; Assert.AreEqual("[[:en:Exemplum#外部リンク|Exemplum#External links]]", translator.ReplaceLink(link, "example").ToString()); // 表示名あり link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "External links"; link.PipeTexts.Add(new TextElement("Exemplum_1")); Assert.AreEqual("[[:en:Exemplum#外部リンク|Exemplum_1]]", translator.ReplaceLink(link, "example").ToString()); // 記事名だけの内部リンクで赤リンク、処理されない link = new MediaWikiLink(); link.Title = "Nothing Page"; Assert.AreEqual("[[Nothing Page]]", translator.ReplaceLink(link, "example").ToString()); // 見出しあり link = new MediaWikiLink(); link.Title = "Nothing Page"; link.Section = "Section A"; Assert.AreEqual("[[Nothing Page#Section A]]", translator.ReplaceLink(link, "example").ToString()); // 変換パターンに該当する見出しの場合 link = new MediaWikiLink(); link.Title = "Nothing Page"; link.Section = "External links"; Assert.AreEqual("[[Nothing Page#外部リンク]]", translator.ReplaceLink(link, "example").ToString()); // 表示名あり link = new MediaWikiLink(); link.Title = "Nothing Page"; link.PipeTexts.Add(new TextElement("Dummy Link")); Assert.AreEqual("[[Nothing Page|Dummy Link]]", translator.ReplaceLink(link, "example").ToString()); // [[Apollo 17]] のように文字参照が入っていても処理できる link = new MediaWikiLink(); link.Title = "Fuji (Spacecraft)"; Assert.AreEqual("[[ふじ (宇宙船)|Fuji (Spacecraft)]]", translator.ReplaceLink(link, "example").ToString()); } /// /// ReplaceLinkメソッドテストケース(サブページ)。 /// [Test] public void TestReplaceLinkSubpage() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); MediaWikiLink link; // 親記事名も全て指定したサブページ // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため link = new MediaWikiLink(); link.Title = "Template:Citation needed/Doc"; Assert.AreEqual("[[Template:要出典|Template:Citation needed/Doc]]", translator.ReplaceLink(link, "Template:Citation needed").ToString()); // 親記事名を省略し別途指定 link = new MediaWikiLink(); link.Title = "/Doc"; link.IsSubpage = true; Assert.AreEqual("[[Template:要出典|/Doc]]", translator.ReplaceLink(link, "Template:Citation needed").ToString()); // ../形式でのサブページ // ※ この形式は2012年2月現在未対応で渡す方法も無い、暫定対応の処理が動く link = new MediaWikiLink(); link.Title = "../Doc"; Assert.AreEqual("[[../Doc]]", translator.ReplaceLink(link, "Template:Citation needed").ToString()); Assert.IsTrue(translator.Log.EndsWith( "[[../Doc]] → " + Environment.NewLine + "→ ../Doc は、現在のツールでは処理できないページ名です。" + Environment.NewLine)); } /// /// ReplaceLinkメソッドテストケース(カテゴリ)。 /// [Test] public void TestReplaceLinkCategory() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("ja"); translator.To = mock.GetMediaWiki("en"); MediaWikiLink link; // 記事名だけの内部リンクで言語間リンクあり、変換先言語でのカテゴリとなる // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため link = new MediaWikiLink(); link.Title = "Category:宇宙船"; Assert.AreEqual("[[Category:Manned spacecraft]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // ソートキーあり link = new MediaWikiLink(); link.Title = "Category:宇宙船"; link.PipeTexts.Add(new TextElement("すへえすしつふつう")); Assert.AreEqual("[[Category:Manned spacecraft|すへえすしつふつう]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 記事名だけの内部リンクで言語間リンクなし、変換元言語へのリンクとなり元のカテゴリはコメントとなる translator.To = mock.GetMediaWiki("it"); link = new MediaWikiLink(); link.Title = "Category:宇宙船"; Assert.AreEqual("[[:ja:Category:宇宙船]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // ソートキーあり link = new MediaWikiLink(); link.Title = "Category:宇宙船"; link.PipeTexts.Add(new TextElement("すへえすしつふつう")); Assert.AreEqual("[[:ja:Category:宇宙船]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // 記事名だけの内部リンクで赤リンク、処理されない link = new MediaWikiLink(); link.Title = "Category:xx国の宇宙船"; Assert.AreEqual("[[Category:xx国の宇宙船]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); // ソートキーあり link = new MediaWikiLink(); link.Title = "Category:xx国の宇宙船"; link.PipeTexts.Add(new TextElement("すへえすしつふつう")); Assert.AreEqual("[[Category:xx国の宇宙船|すへえすしつふつう]]", translator.ReplaceLink(link, "スペースシップツー").ToString()); } /// /// ReplaceLinkメソッドテストケース(ファイル)。 /// [Test] public void TestReplaceLinkFile() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); MediaWikiLink link; // 画像などのファイルについては、名前空間を他国語に置き換えるだけ // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため link = new MediaWikiLink(); link.Title = "File:Kepler22b-artwork.jpg"; Assert.AreEqual("[[ファイル:Kepler22b-artwork.jpg]]", translator.ReplaceLink(link, "Kepler-22b").ToString()); // パラメータあり link = new MediaWikiLink(); link.Title = "File:Kepler22b-artwork.jpg"; link.PipeTexts.Add(new TextElement("thumb")); link.PipeTexts.Add(new TextElement("right")); link.PipeTexts.Add(new TextElement("Artist's conception of Kepler-22b.")); Assert.AreEqual("[[ファイル:Kepler22b-artwork.jpg|thumb|right|Artist's conception of Kepler-22b.]]", translator.ReplaceLink(link, "Kepler-22b").ToString()); // ja→enの場合もちゃんと置き換える(en→jaはFileのままでも使えるが逆は置き換えないと動かない) translator.From = mock.GetMediaWiki("ja"); translator.To = mock.GetMediaWiki("en"); link = new MediaWikiLink(); link.Title = "ファイル:Kepler22b-artwork.jpg"; Assert.AreEqual("[[File:Kepler22b-artwork.jpg]]", translator.ReplaceLink(link, "ケプラー22b").ToString()); } /// /// ReplaceLinkメソッドテストケース(仮リンク)。 /// [Test] public void TestReplaceLinkLinkInterwiki() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); // 見出しの変換パターンを設定 translator.HeadingTable = new TranslationTable(); IDictionary dic = new Dictionary(); dic["en"] = "External links"; dic["ja"] = "外部リンク"; translator.HeadingTable.Add(dic); translator.HeadingTable.From = "en"; translator.HeadingTable.To = "ja"; MediaWikiLink link; // 記事名だけの内部リンクで言語間リンクなし、変換元言語へのリンクとなる // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため link = new MediaWikiLink(); link.Title = "Exemplum"; Assert.AreEqual("{{仮リンク|Exemplum|en|Exemplum|label=Exemplum}}", translator.ReplaceLink(link, "example").ToString()); // 見出しあり link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "Three examples of exempla"; Assert.AreEqual("{{仮リンク|Exemplum#Three examples of exempla|en|Exemplum#Three examples of exempla|label=Exemplum#Three examples of exempla}}", translator.ReplaceLink(link, "example").ToString()); // 変換パターンに該当する見出しの場合 link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "External links"; Assert.AreEqual("{{仮リンク|Exemplum#外部リンク|en|Exemplum#External links|label=Exemplum#External links}}", translator.ReplaceLink(link, "example").ToString()); // 表示名あり link = new MediaWikiLink(); link.Title = "Exemplum"; link.Section = "External links"; link.PipeTexts.Add(new TextElement("Exemplum_1")); Assert.AreEqual("{{仮リンク|Exemplum#外部リンク|en|Exemplum#External links|label=Exemplum_1}}", translator.ReplaceLink(link, "example").ToString()); // 言語間リンクありの場合、仮リンクは使用されない link = new MediaWikiLink(); link.Title = "Example.com"; Assert.AreEqual("[[Example.com|Example.com]]", translator.ReplaceLink(link, "example").ToString()); // 記事名だけの内部リンクで赤リンクも、使用されない link = new MediaWikiLink(); link.Title = "Nothing Page"; Assert.AreEqual("[[Nothing Page]]", translator.ReplaceLink(link, "example").ToString()); } /// /// ReplaceTemplateメソッドテストケース。 /// [Test] public void TestReplaceTemplate() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); MediaWikiTemplate template; // テンプレート名だけで言語間リンクあり、変換先言語でのテンプレートとなる // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため template = new MediaWikiTemplate("Citation needed"); Assert.AreEqual("{{要出典}}", translator.ReplaceTemplate(template, "example").ToString()); // パラメータあり template = new MediaWikiTemplate("Citation needed"); template.PipeTexts.Add(new TextElement("date=January 2012")); Assert.AreEqual("{{要出典|date=January 2012}}", translator.ReplaceTemplate(template, "example").ToString()); // テンプレート名だけで言語間リンクなし、変換元言語へのリンクとなり元のテンプレートはコメントとなる template = new MediaWikiTemplate("Wiktionary"); Assert.AreEqual("[[:en:Template:Wiktionary]]", translator.ReplaceTemplate(template, "example").ToString()); // パラメータあり template = new MediaWikiTemplate("Wiktionary"); template.PipeTexts.Add(new TextElement("Sample")); Assert.AreEqual("[[:en:Template:Wiktionary]]", translator.ReplaceTemplate(template, "example").ToString()); // テンプレート名だけで赤リンク、処理されない template = new MediaWikiTemplate("Invalid Template"); Assert.AreEqual("{{Invalid Template}}", translator.ReplaceTemplate(template, "example").ToString()); // パラメータあり template = new MediaWikiTemplate("Invalid Template"); template.PipeTexts.Add(new TextElement("parameter=1")); Assert.AreEqual("{{Invalid Template|parameter=1}}", translator.ReplaceTemplate(template, "example").ToString()); // システム定義変数、処理されない template = new MediaWikiTemplate("PAGENAME"); Assert.AreEqual("{{PAGENAME}}", translator.ReplaceTemplate(template, "example").ToString()); } /// /// ReplaceTemplateメソッドテストケース(入れ子)。 /// [Test] public void TestReplaceTemplateNested() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); MediaWikiTemplate template; MediaWikiLink link; ListElement list; // テンプレート名だけで言語間リンクあり、入れ子も処理される // ※ 以下オブジェクトを毎回作り直しているのは、更新されてしまうケースがあるため template = new MediaWikiTemplate("Citation needed"); template.PipeTexts.Add(new TextElement("date=January 2012")); list = new ListElement(); list.Add(new TextElement("note=See also ")); link = new MediaWikiLink(); link.Title = "Fuji (Spacecraft)"; list.Add(link); template.PipeTexts.Add(list); Assert.AreEqual("{{要出典|date=January 2012|note=See also [[ふじ (宇宙船)|Fuji (Spacecraft)]]}}", translator.ReplaceTemplate(template, "example").ToString()); // テンプレート名だけで言語間リンクなし、入れ子は処理されない template = new MediaWikiTemplate("Wiktionary"); template.PipeTexts.Add(new TextElement("Sample")); list = new ListElement(); list.Add(new TextElement("note=See also ")); link = new MediaWikiLink(); link.Title = "Fuji (Spacecraft)"; list.Add(link); template.PipeTexts.Add(list); Assert.AreEqual("[[:en:Template:Wiktionary]]", translator.ReplaceTemplate(template, "example").ToString()); // テンプレート名だけで赤リンク、入れ子は処理されない template = new MediaWikiTemplate("Invalid Template"); template.PipeTexts.Add(new TextElement("parameter=1")); list = new ListElement(); list.Add(new TextElement("note=See also ")); link = new MediaWikiLink(); link.Title = "Fuji (Spacecraft)"; list.Add(link); template.PipeTexts.Add(list); Assert.AreEqual("{{Invalid Template|parameter=1|note=See also [[Fuji (Spacecraft)]]}}", translator.ReplaceTemplate(template, "example").ToString()); } /// /// ReplaceHeadingメソッドテストケース。 /// [Test] public void TestReplaceHeading() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("en"); translator.To = mock.GetMediaWiki("ja"); // 見出しの変換パターンを設定 translator.HeadingTable = new TranslationTable(); IDictionary dic = new Dictionary(); dic["en"] = "External links"; dic["ja"] = "外部リンク"; translator.HeadingTable.Add(dic); translator.HeadingTable.From = "en"; translator.HeadingTable.To = "ja"; MediaWikiHeading heading = new MediaWikiHeading(); // 対訳表に登録されていない見出し // ※ 以下リストを毎回作り直しているのは、更新されてしまうケースがあるため heading.Level = 2; heading.Add(new TextElement(" invalid section ")); Assert.AreEqual("== invalid section ==", translator.ReplaceHeading(heading, "example").ToString()); // 対訳表に登録されている見出し heading.Clear(); heading.Add(new TextElement(" External links ")); Assert.AreEqual("==外部リンク==", translator.ReplaceHeading(heading, "example").ToString()); // 一部が内部リンク等になっている場合、対訳表とは一致しない heading.Clear(); heading.Add(new TextElement(" External ")); heading.Add(new MediaWikiLink("link")); heading.Add(new TextElement("s ")); Assert.AreEqual("== External [[link]]s ==", translator.ReplaceHeading(heading, "example").ToString()); } /// /// ReplaceHeadingメソッドテストケース(入れ子)。 /// [Test] public void TestReplaceHeadingNested() { TestMediaWikiTranslator translator = new TestMediaWikiTranslator(); MockFactory mock = new MockFactory(); translator.From = mock.GetMediaWiki("ja"); translator.To = mock.GetMediaWiki("en"); // 見出しの変換パターンを設定 translator.HeadingTable = new TranslationTable(); IDictionary dic = new Dictionary(); translator.HeadingTable.Add(dic); translator.HeadingTable.From = "ja"; translator.HeadingTable.To = "en"; MediaWikiHeading heading = new MediaWikiHeading(); // 対訳表に登録されていない見出しの場合、入れ子も処理される // ※ 以下リストを毎回作り直しているのは、更新されてしまうケースがあるため heading.Level = 3; heading.Add(new TextElement(" ")); heading.Add(new MediaWikiLink("宇宙旅行")); heading.Add(new MediaWikiTemplate("ref-en")); heading.Add(new TextElement(" ")); Assert.AreEqual("=== [[Space tourism|宇宙旅行]]{{En icon}} ===", translator.ReplaceHeading(heading, "スペースシップツー").ToString()); // 対訳表に登録されている見出しの場合、入れ子は処理されない dic["ja"] = "[[宇宙旅行]]{{ref-en}}"; dic["en"] = "[[弾道飛行]]{{ref-en}}"; heading.Clear(); heading.Add(new TextElement(" ")); heading.Add(new MediaWikiLink("宇宙旅行")); heading.Add(new MediaWikiTemplate("ref-en")); heading.Add(new TextElement(" ")); Assert.AreEqual("===[[弾道飛行]]{{ref-en}}===", translator.ReplaceHeading(heading, "スペースシップツー").ToString()); } #endregion #region 全体テストケース /// /// テストデータを用い、Runを通しで実行するテストケース。基本動作。 /// [Test] public void TestExampleIgnoreHeading() { MockFactory mock = new MockFactory(); MediaWiki from = mock.GetMediaWiki("en"); MediaWikiTranslator translator = new MediaWikiTranslator(); translator.From = from; translator.To = mock.GetMediaWiki("ja"); translator.To.LinkInterwikiFormat = null; translator.HeadingTable = new TranslationTable(); translator.HeadingTable.From = "en"; translator.HeadingTable.To = "ja"; translator.Run("example"); // テストデータの変換結果を期待される結果と比較する // バージョン表記部分は毎回変化するため、期待される結果のうち該当部分を更新する //System.Diagnostics.Debug.WriteLine("TranslateMediaWikiTest.TestExampleIgnoreHeading Text > " + translate.Text); Assert.AreEqual( File.ReadAllText(Path.Combine(resultDir, "example_定型句なし.txt")).Replace("