/*
 * Copyright (c) 2005- Shinji Kashihara.
 * All rights reserved. This program are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at epl-v10.html.
 */
package jp.sourceforge.mergedoc.pleiades.resource;

import java.util.List;

import junit.framework.TestCase;

/**
 * テスト・クラスです。
 * <p>
 * @author cypher256
 */
public class TranslationStringTest extends TestCase {

	/**
	 * リスト出力
	 * @param list
	 */
	private void printEach(List<TranslationString> list) {
		System.out.println("-------------------------------------------------------------------");
		if (list == null) {
			System.out.println("null");
		}
		else {
			for (TranslationString s : list) {
				System.out.println("→ " + s);
			}
		}
	}

	//-------------------------------------------------------------------------

	/** トリム */
	public void testTrim() {

		TranslationString t = null;

		// 英語 trim []
		t = new TranslationString("[ All configurations ]");
		System.out.println(t.trim());
		assertEquals("[ All configurations ]", t.toString());
		assertEquals("All configurations", t.trim());

		// 英語 trim -
		t = new TranslationString("-- End of Stream Output --");
		System.out.println(t.trim());
		assertEquals("-- End of Stream Output --", t.toString());
		assertEquals("End of Stream Output", t.trim());

		// 英語 trim <!--
		t = new TranslationString("<!-- End of Stream Output -->");
		System.out.println(t.trim());
		assertEquals("<!-- End of Stream Output -->", t.toString());
		assertEquals("End of Stream Output", t.trim());

		// 英語 trim <!--
		t = new TranslationString("\"  \"");
		System.out.println(t.trim());
		assertEquals("\"  \"", t.toString());
		assertEquals("", t.trim());

		// 英語 HTML タグ
		t = new TranslationString("<html><p style=\"font-family:Lucida Grande;\">OSGi, Web frameworks are detected in the project <a href=\"configure\">Configure</a></p></html>");
		System.out.println(t.trim());
		assertEquals("OSGi, Web frameworks are detected in the project <a href=\"configure\">Configure</a>", t.trim());

		// 英語 HTML タグ (不正)
		t = new TranslationString("<html>One-line methods<html>");
		System.out.println(t.trim());
		assertEquals("One-line methods", t.trim());

		// 英語 HTML タグ (style)
		t = new TranslationString("<html><head><style>¥nxxx¥n</style><style>yyy</style></head><body> zzz <b><a href=\"updates\">Updates</a></b> 000.</body></html>");
		System.out.println(t.trim());
		assertEquals("zzz <b><a href=\"updates\">Updates</a></b> 000.", t.trim());
		assertEquals("zzz <b><a href=\"updates\">Updates</a></b> 000", t.trimForce());

		// 日本語 HTML タグ
		t = new TranslationString("<i>なし</i>");
		System.out.println(t.trim());
		assertEquals("なし", t.trim());

		// 英語 かっこ + .
		t = new TranslationString("10.5.2, 10.6.10).");
		System.out.println(t.trim());
		assertEquals("10.5.2, 10.6.10).", t.toString());
		assertEquals("10.5.2, 10.6.10).", t.trim());
		assertEquals("10.5.2, 10.6.10", t.trimForce());
		assertEquals("10.5.2, 10.6.10)。", t.revert());

		// HTML タグ閉じ前に空白
		t = new TranslationString("<html><head><style>; </style></head><body><a >xxx</a></body></html>");
		assertEquals("xxx", t.trim());

		// 末尾 ! で隣接空白はトリムしない
		t = new TranslationString("add entries prefixed with !");
		assertEquals("add entries prefixed with !", t.trim());
		assertEquals("add entries prefixed with !", t.trimForce());

		// trim 後の文字列の trimForce と trimForce のみの結果が同じであることの確認
		t = new TranslationString("<form><p>aaa</p><li>bbb.</li></form>");
		assertEquals("<p>aaa</p><li>bbb.</li>", t.trim());
		assertEquals("aaa</p><li>bbb", t.trimForce());
		t = new TranslationString("<form><p>aaa</p><li>bbb.</li></form>");
		t = new TranslationString(t.trim());
		assertEquals("aaa</p><li>bbb", t.trimForce());
	}

	/** 分割 */
	public void testSplit() {

		TranslationString t = null;

		// 日本語 1 つ
		t = new TranslationString("あいうえお。");
		List<TranslationString> list = t.split();
		printEach(list);
		assertEquals(null, list);

		// 日本語 複数
		t = new TranslationString("あいうえお。  かきくけこ。");
		list = t.split();
		printEach(list);
		assertEquals("あいうえお。  ", list.get(0).toString());
		assertEquals("かきくけこ。", list.get(1).toString());

		// 英語 複数、- の前後が数値、非数値
		t = new TranslationString("aaa bbb. 1.23 abc - xxx yyy. 1 - 2.");
		t.trimForce(); // 末尾を削除してみる
		list = t.split();
		printEach(list);
		assertEquals("aaa bbb. ", list.get(0).toString());
		assertEquals("1.23 abc - ", list.get(1).toString());
		assertEquals("1.23 abc", list.get(1).trim());
		assertEquals("xxx yyy. ", list.get(2).toString());
		assertEquals("1 - 2.", list.get(3).toString());

		// 英語 句点分割されない ドット＋改行＋空白 (整形済みテキスト)
		t = new TranslationString("Connector to submit code to the R-GUI (Windows).\n Note:\n - The Connector requires .NET-Framework\n - For some operations the connector uses the system-clipboard (previous content will be deleted).");
		list = t.split();
		assertNull(list);

		// 英語 句点分割されない ドット以外＋改行＋文字
		t = new TranslationString("Analyze the application Method Coverage. See what methods were\nexecuted.");
		list = t.split();
		assertNull(list);

		// 英語 句点分割 ドット＋改行＋文字
		t = new TranslationString("A required property is missing from the Common Base Event.\nProperty: {0}");
		list = t.split();
		printEach(list);
		assertEquals("A required property is missing from the Common Base Event.\n", list.get(0).toString());
		assertEquals("Property: ", list.get(1).toString());
		assertEquals("{0}", list.get(2).toString());

		// 日本語 句点分割 ドット＋改行＋文字 (上記と分割数は同じでないと Generator で分割されない)
		t = new TranslationString("共通ベース・イベントに必要なプロパティーがありません。\nプロパティー: {0}");
		list = t.split();
		printEach(list);
		assertEquals("共通ベース・イベントに必要なプロパティーがありません。\n", list.get(0).toString());
		assertEquals("プロパティー: ", list.get(1).toString());
		assertEquals("{0}", list.get(2).toString());

		// 日本語 句点分割されない
		String[] text = {
			"使用可能にすると、メソッド/コンストラクターの呼び出しに渡されるときに可変引数のキャストが必要な場合に、コンパイラーはエラーまたは警告を出します。\n",
			"(例えば、引数 (\"foo\", null) で呼び出される Class.getMethod(String name, Class ... args )。)"
		};
		t = new TranslationString(text[0] + text[1]);
		list = t.split();
		assertEquals(text[0], list.get(0).toString());
		assertEquals(text[1], list.get(1).toString());

		// 英語 () 分割
		t = new TranslationString("aaa (Incubation)");
		list = t.split();
		printEach(list);
		assertEquals("aaa ", list.get(0).toString());
		assertEquals("(Incubation)", list.get(1).toString());
		assertEquals("Incubation", list.get(1).trim());

		// 英語 () 分割 + . -> 復元
		t = new TranslationString("aaa (label).");
		list = t.split();
		printEach(list);
		assertEquals("aaa ", list.get(0).toString());
		assertEquals("(label).", list.get(1).toString());
		assertEquals("label", list.get(1).trim());
		assertEquals("(ラベル)。", list.get(1).revert("ラベル"));

		// 英語 省略を示す .
		t = new TranslationString("aaa Inc. xxx.");
		list = t.split();
		printEach(list);
		assertEquals(null, list);

		// 英語 Eclipse エラーコード
		t = new TranslationString("IWAE0005E IWAJ0131I Cannot add:");
		list = t.split();
		printEach(list);
		assertEquals(null, list);
		assertEquals("IWAE0005E IWAJ0131I Cannot add:", t.toString());
		assertEquals("IWAJ0131I Cannot add:", t.trim());

		// 英語 ... の前に空白
		t = new TranslationString(
			"MyISAM uses special tree-like cache to make bulk inserts (that is, INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., and LOAD DATA INFILE) faster. " +
			"This variable limits the size of the cache tree in bytes per thread. " +
			"Setting it to 0 will disable this optimisation. " +
			"Note: " +
			"this cache is only used when adding data to non-empty table. " +
			"Default value is 8 MB.");
		list = t.split();
		printEach(list);
		assertEquals(6, list.size());

		// 日本語 :
		t = new TranslationString("これは a: b です。");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());

		// 日本語 : が () で囲まれている
		t = new TranslationString("これは (a: b) です。");
		list = t.split();
		printEach(list);
		assertEquals(null, list);

		// 日本語 : の後に {n} がなく、かつ 句読点以外の文字がある
		t = new TranslationString("表示中の id: エラーです。");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());

		// 英語 句点分割 - の後に {n} の場合、分割しない
		// 訳：データ・セット {0} にデータ・ソースがありません。～
		t = new TranslationString("No data source available for data set - {0}, please select a data source");
		list = t.split();
		printEach(list);
		assertTrue(list == null);

		// 英語 句点分割 : の後に {n} の場合、分割しない
		// 訳：{1} 用の非デフォルト・ロケーション\: {0} は使用中です
		t = new TranslationString("The non default location: {0} for {1} is in use.");
		list = t.split();
		printEach(list);
		assertTrue(list == null);

		// 英語 句点分割 : の後に {n} の場合、分割しない、{n} の後に単語が無い場合は分割する
		t = new TranslationString("IWAE0036E URI Name: {0}; File name: {1}");
		list = t.split();
		printEach(list);
		assertEquals("URI Name: ", list.get(0).toString());
		assertEquals("{0}; ", list.get(1).toString());
		assertEquals("File name: ", list.get(2).toString());
		assertEquals("{1}", list.get(3).toString());

		// 日本語 句点分割 :
		t = new TranslationString("IWAE0036E URI 名: {0}、ファイル名: {1}");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("URI 名: {0}、ファイル名: ", list.get(0).toString());
		assertEquals("{1}", list.get(1).toString());

		// 日本語 句点分割
		t = new TranslationString("''{0}'' という名前の型は ''{1}'' 内にインポート (単一の型のインポート) されています (コンパイル単位は同じ名前で型をインポートおよび宣言できません)");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("''{0}'' という名前の型は ''{1}'' 内にインポート (単一の型のインポート) されています ", list.get(0).toString());
		assertEquals("(コンパイル単位は同じ名前で型をインポートおよび宣言できません)", list.get(1).toString());

		// 英語 句点分割 () 入れ子
		t = new TranslationString(
			"Specify filters to control the resource copy process. " +
			"(&lt;name&gt; is a file name pattern (only * wild-cards allowed) or the name of a folder which ends with '/')");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Specify filters to control the resource copy process. ",
			list.get(0).toString());
		assertEquals("(&lt;name&gt; is a file name pattern (only * wild-cards allowed) or the name of a folder which ends with '/')",
			list.get(1).toString());

		// 英語 句点分割 (ヘルプ) spllit & trim
		t = new TranslationString(
			"JDT Core options control the behavior of core features such as the Java compiler, code formatter, code assist, and other core behaviors.&nbsp; " +
			"The APIs for accessing the options are defined in <a href=\"../reference/api/org/eclipse/jdt/core/JavaCore.html\"><b>JavaCore</b></a>.&nbsp; " +
			"Options can be accessed as a group as follows: ");
		list = t.split();
		printEach(list);
		assertEquals("JDT Core options control the behavior of core features such as the Java compiler, code formatter, code assist, and other core behaviors.&nbsp; ",
			list.get(0).toString());
		assertEquals("The APIs for accessing the options are defined in <a href=\"../reference/api/org/eclipse/jdt/core/JavaCore.html\"><b>JavaCore</b></a>.&nbsp; ",
			list.get(1).toString());
		assertEquals("Options can be accessed as a group as follows:",
			list.get(2).toString());

		assertEquals("JDT Core options control the behavior of core features such as the Java compiler, code formatter, code assist, and other core behaviors.",
			list.get(0).trim());
		assertEquals("The APIs for accessing the options are defined in <a href=\"../reference/api/org/eclipse/jdt/core/JavaCore.html\"><b>JavaCore</b></a>.",
			list.get(1).trim());
		assertEquals("Options can be accessed as a group as follows:",
			list.get(2).trim());

		// 英語 セミコロン + 空白
		t = new TranslationString("aaa productName; xxx");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("aaa productName; ", list.get(0).toString());
		assertEquals("xxx", list.get(1).toString());

		// 英語 セミコロン HTML 参照文字 (分割しない)
		t = new TranslationString("aaa &productName; xxx");
		list = t.split();
		printEach(list);
		assertTrue(list == null);
		assertEquals("aaa &productName; xxx", t.toString());

		// 日本語 句点分割 (ヘルプ)
		t = new TranslationString(
			"JDT コア・オプションは、Java コンパイラー、コード・フォーマッター、コード・アシスト、 およびその他のコアの振る舞いなど、コア・フィーチャーの振る舞いを制御します。 " +
			"オプションにアクセスするための API は <a href=\"../reference/api/org/eclipse/jdt/core/JavaCore.html\"><b>JavaCore</b></a> で定義されます。 " +
			"オプションには、以下のグループとしてアクセスできます。");
		list = t.split();
		printEach(list);
		assertEquals("JDT コア・オプションは、Java コンパイラー、コード・フォーマッター、コード・アシスト、 およびその他のコアの振る舞いなど、コア・フィーチャーの振る舞いを制御します。 ",
			list.get(0).toString());
		assertEquals("オプションにアクセスするための API は <a href=\"../reference/api/org/eclipse/jdt/core/JavaCore.html\"><b>JavaCore</b></a> で定義されます。 ",
			list.get(1).toString());
		assertEquals("オプションには、以下のグループとしてアクセスできます。",
			list.get(2).toString());

		// 日本語 句点分割 末尾 -
		t = new TranslationString("バンドルのシンボル名に正しくない文字が含まれています。 正しい文字は A-Z a-z 0-9 . _ - です");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("バンドルのシンボル名に正しくない文字が含まれています。 ", list.get(0).toString());
		assertEquals("正しい文字は A-Z a-z 0-9 . _ - です", list.get(1).toString());

		// 英語 句点分割 末尾 -
		t = new TranslationString("Bundle symbolic name contains illegal characters. Legal characters are A-Z a-z 0-9 . _ -");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Bundle symbolic name contains illegal characters. ", list.get(0).toString());
		assertEquals("Legal characters are A-Z a-z 0-9 . _ -", list.get(1).toString());
		assertEquals("Legal characters are A-Z a-z 0-9 . _ -", list.get(1).trim());

		// 日本語 句点分割 -
		t = new TranslationString("Agent Controller 利用不可 - Agent Controller が実行中で接続受け入れ状態であることを確認してください");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Agent Controller 利用不可 - ", list.get(0).toString());
		assertEquals("Agent Controller 利用不可",    list.get(0).trim());
		assertEquals("Agent Controller が実行中で接続受け入れ状態であることを確認してください", list.get(1).toString());

		// 英語 句点分割 -
		t = new TranslationString("Agent Controller Unavailable - Please ensure the Agent Controller is running and accepting connections");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Agent Controller Unavailable - ", list.get(0).toString());
		assertEquals("Agent Controller Unavailable",    list.get(0).trim());
		assertEquals("Please ensure the Agent Controller is running and accepting connections", list.get(1).toString());

		// 英語 句点分割 括弧
		t = new TranslationString("Use default SDK (App Engine - 1.2.0)");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("Use default SDK ", list.get(0).toString());
		assertEquals("(App Engine - ", list.get(1).toString());
		assertEquals("App Engine", list.get(1).trim());
		assertEquals("1.2.0)", list.get(2).toString());
		assertEquals("1.2.0", list.get(2).trim());

		// 英語 句点分割 先頭 ...
		t = new TranslationString("    ... more   ");
		list = t.split();
		printEach(list);
		assertTrue(list == null);
		assertEquals("... more", t.trim());
		assertEquals("more", t.trimForce());

		// 英語 句点分割 HTML
		t = new TranslationString("<html>Do not have an account at github.com? <a href=\"https://github.com\">Sign up</a></html>");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Do not have an account at github.com? ", list.get(0).toString());
		assertEquals("Do not have an account at github.com?", list.get(0).trim());
		assertEquals("<a href=\"https://github.com\">Sign up</a>", list.get(1).toString());

		// 英語 句点分割 HTML 終了タグ
		t = new TranslationString("<html><body><p style=\"margin-top:5px;\">Subscription is active until November 30, 2017.</p><p>For non-commercial open source development only</p></body></html>");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Subscription is active until November 30, 2017.</p>", list.get(0).toString());
		assertEquals("Subscription is active until November 30, 2017.", list.get(0).trim());
		assertEquals("Subscription is active until November 30, 2017", list.get(0).trimForce());
		assertEquals("<p>For non-commercial open source development only", list.get(1).toString());
		assertEquals("For non-commercial open source development only", list.get(1).trim());

		// 英語 句点分割 不正 HTML (</html> 2 つ、本文に > 含む)
		t = new TranslationString("<html><head><style>\nbody, div, td, p {font-family:'Lucida Grande'; font-size:13pt;} a {font-family:'Lucida Grande'; font-size:13pt;} code {font-size:13pt;} </style><style>body {background: #3c3f41;}</style></head><body><html>A new <a href='https://sites.google.com/a/android.com/tools/recent'>Android Studio</a> 2.3 Beta 1 is available in the beta channel.<p/> 2.3 Beta 1 includes new functionality, bug fixes, and performance improvements.<br/><br/>We recommend updating to this version.<br/><br/>Please continue to file feedback (Help > Submit Feedback) if you see issues in this release.<br/><br/> </html></body></html>");
		list = t.split();
		printEach(list);
		assertEquals("A new <a href='https://sites.google.com/a/android.com/tools/recent'>Android Studio</a> 2.3 Beta 1 is available in the beta channel.<p/>2.3 Beta 1 includes new functionality, bug fixes, and performance improvements.<br/><br/>We recommend updating to this version.<br/><br/>Please continue to file feedback (Help > Submit Feedback) if you see issues in this release.", t.trim());
		assertEquals(4, list.size());
		assertEquals("A new <a href='https://sites.google.com/a/android.com/tools/recent'>Android Studio</a> 2.3 Beta 1 is available in the beta channel.<p/>", list.get(0).toString());
		assertEquals("2.3 Beta 1 includes new functionality, bug fixes, and performance improvements.<br/><br/>", list.get(1).toString());
		assertEquals("We recommend updating to this version.<br/><br/>", list.get(2).toString());
		assertEquals("Please continue to file feedback (Help > Submit Feedback) if you see issues in this release.", list.get(3).toString());

		// 英語 句点分割 HTML br 連続
		t = new TranslationString("<html>Updates are available for the Android SDK and Tools<br><br>Android SDK updates ensure you have the latest features and enhancements.<br>Android Studio will update the following components:</html>");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("Updates are available for the Android SDK and Tools<br><br>", list.get(0).toString());
		assertEquals("Updates are available for the Android SDK and Tools", list.get(0).trim());
		assertEquals("Android SDK updates ensure you have the latest features and enhancements.<br>", list.get(1).toString());
		assertEquals("Android SDK updates ensure you have the latest features and enhancements.", list.get(1).trim());
		assertEquals("Android SDK updates ensure you have the latest features and enhancements", list.get(1).trimForce());
		assertEquals("Android Studio will update the following components:", list.get(2).trim());
		assertEquals("Android Studio will update the following components", list.get(2).trimForce());

		// 英語 句点分割 HTML 句読点に続く /b+空白
		t = new TranslationString("<b>Unindexed remote maven repositories found.</b> <a href=\"#disable\">Disable...</a>");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("<b>Unindexed remote maven repositories found.</b> ", list.get(0).toString());
		assertEquals("Unindexed remote maven repositories found.", list.get(0).trim());
		assertEquals("<a href=\"#disable\">Disable...</a>", list.get(1).toString());
		assertEquals("Disable...", list.get(1).trim());

		// 英語 句点分割 HTML 句読点に続く /b+<br>+空白
		t = new TranslationString("<html><b>Android NDK location:</b><br> The directory where the Android NDK is located. This location will be saved as ndk.dir property in the local.properties file.</html>");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("<b>Android NDK location:</b><br>", list.get(0).toString());
		assertEquals("The directory where the Android NDK is located. ", list.get(1).toString());
		assertEquals("This location will be saved as ndk.dir property in the local.properties file.", list.get(2).toString());

		// 英語 句点分割 HTML head link タグ
		t = new TranslationString("<html>\n<head>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"css/tips.css\">\n</head>\n<body>\n\n\n<p>To select multiple words, press <span class=\"shortcut\">Alt+Shift</span>, place\n    the caret at each word to be selected and double-click the left mouse button.</p>\n<p class=\"image\"><img src=\"images/multiselection_words.png\"></p>\n</body>\n</html>");
		list = t.split();
		assertTrue(list == null);
		assertEquals("To select multiple words, press <span class=\"shortcut\">Alt+Shift</span>, place the caret at each word to be selected and double-click the left mouse button.", t.trim());
		assertEquals("To select multiple words, press <span class=\"shortcut\">Alt+Shift</span>, place the caret at each word to be selected and double-click the left mouse button", t.trimForce());

		// 英語 句点分割 HTML ブロックタグ前後の空白無視確認
		t = new TranslationString("<html>\n<head>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"css/tips.css\">\n</head>\n<body>\n\n<p>All your most indispensable VCS commands are just one-click away...</p>\n<p>\nChoose <span class=\"control\">VCS | VCS Operations Popup</span>\non the main menu, and get a popup with the VCS commands that are relevant to the current context:\n</p>\n\n<p class=\"image\"><img width=\"322\" height=\"302\" src=\"images/vcsQuickList.png\"></p>\n\n</body>\n</html>");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("All your most indispensable VCS commands are just one-click away...", list.get(0).trim());
		assertEquals("Choose <span class=\"control\">VCS | VCS Operations Popup</span> on the main menu, and get a popup with the VCS commands that are relevant to the current context:", list.get(1).trim());

		// 英語 句点分割 HTML ul
		t = new TranslationString("<html>\n<head>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"css/tips.css\">\n</head>\n<body>\n    <p>\n        There are two ways of closing all tabs in the editor, except the current one:</p>\n<ul>\n<li>First, right-click the editor tab, and choose <span class=\"control\">Close Others</span> on the context menu.</li>\n<li>Second, keeping the Alt key pressed, click <img src=\"images/close1.png\"/> on the editor tab.</li>\n</ul>   \n    <p class=\"image\">\n        <img src=\"images/close_others.png\"></p>\n</body>\n</html>");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("There are two ways of closing all tabs in the editor, except the current one:", list.get(0).trim());
		assertEquals("First, right-click the editor tab, and choose <span class=\"control\">Close Others</span> on the context menu.", list.get(1).trim());
		assertEquals("Second, keeping the Alt key pressed, click <img src=\"images/close1.png\"/> on the editor tab.", list.get(2).trim());

		// 英語 句点分割 HTML h1
		t = new TranslationString("<html>\n<head>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"css/tips.css\">\n</head>\n<body>\n    <h1>\n        Welcome to <span class=\"product\">productName;</span> <span class=\"version\">&majorVersion;.&minorVersion;</span></h1>\n    <p>\n        You can quickly get familiar with the main features of the IDE by reading these tips. You may try out\n        the features described in the tips while this dialog stays open on the screen. If you close the dialog,\n        you can always get back to it from the <span class=\"control\">Help | Tip of the Day</span>\n        main menu item.</p>\n</body>\n</html>");
		list = t.split();
		printEach(list);
		assertEquals(4, list.size());
		assertEquals("Welcome to <span class=\"product\">productName;</span> <span class=\"version\">&majorVersion;.&minorVersion;</span>", list.get(0).trim());

		// 英語 句点分割 HTML div
		t = new TranslationString("<html><head><style> body, div, td, p {font-family:'.SF NS Text'; font-size:13pt; color:#bbbbbb;} a {font-family:'.SF NS Text'; font-size:13pt; color:#589df6;} code {font-size:13pt;} ul {list-style-image:url('jar:file:/Applications/IntelliJ%20IDEA.app/Contents/lib/icons.jar!/general/mdot-white.png');} </style></head><body>メソッドを java.lang.Object にオーバーライドします<br><div style='margin-top: 5px'><font size='2'>Click or press ⌘U to navigate</font></div></body></html>");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("メソッドを java.lang.Object にオーバーライドします<br>", list.get(0).toString());
		assertEquals("メソッドを java.lang.Object にオーバーライドします", list.get(0).trim());
		assertEquals("<div style='margin-top: 5px'><font size='2'>Click or press ⌘U to navigate</font>", list.get(1).toString());
		assertEquals("Click or press ⌘U to navigate", list.get(1).trim());

		// 英語 句点分割 HTML table
		t = new TranslationString("<html><table><tr><td>col11</td><td><a href=\"x\">col12</a></td></tr><tr><td>col2</td></tr></table></html>");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("col11", list.get(0).trim());
		assertEquals("col12", list.get(1).trim());
		assertEquals("col2", list.get(2).trim());

		// 英語 スラッシュ 2 つ
		t = new TranslationString("Parameters//Type parameter");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("Parameters//", list.get(0).toString());
		assertEquals("Parameters", list.get(0).trim());
		assertEquals("Type parameter", list.get(1).toString());

		// 英語 スラッシュ 2 つ (URL は分割しない)
		t = new TranslationString("'http://www.sample-url.org/doc/' or 'file:///c\\:/xxx/doc'");
		list = t.split();
		printEach(list);
		assertNull(list);

		// タグを含む文章は分割しない (タグ隣接空白) 後
		t = new TranslationString("Wrap with <br>");
		list = t.split();
		printEach(list);
		assertNull(list);
		assertEquals("Wrap with <br>", t.trim());

		// タグを含む文章は分割しない (タグ隣接空白) 後
		t = new TranslationString("Wrap with <p>");
		list = t.split();
		printEach(list);
		assertNull(list);
		assertEquals("Wrap with <p>", t.trim());

		// タグを含む文章は分割しない (タグ隣接空白) 前
		t = new TranslationString("<p> ブロックでテキストを折り返し");
		list = t.split();
		printEach(list);
		assertNull(list);
		assertEquals("<p> ブロックでテキストを折り返し", t.trim());

		// タグを含む文章は分割しない (タグ隣接空白) 前後
		t = new TranslationString("Discard empty <p> elements");
		list = t.split();
		printEach(list);
		assertNull(list);
		assertEquals("Discard empty <p> elements", t.trim());

		// タグではないものは分割しない (隣接空白)
		t = new TranslationString("<{0}> unmatched in documentation");
		list = t.split();
		printEach(list);
		assertNull(list);
		assertEquals("<{0}> unmatched in documentation", t.trim());

		// 括弧に隣接する &nbsp;
		t = new TranslationString("<a href='FindOptions'>Find Options...</a>&nbsp;(⌥⇧⌘F7)");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("<a href='FindOptions'>Find Options...</a>&nbsp;", list.get(0).toString());
		assertEquals("Find Options...", list.get(0).trim());

		// ; が HTML 参照文字の末尾の場合は分割しない
		t = new TranslationString("&productName; aaa. bbb.");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());

		// HTML コメントタグ (ブロックタグ扱い)
		t = new TranslationString("<html>\n<body>\nThis inspection reports all fields, methods or classes, found in the specified inspection\nscope, that may have a <b><font color=\"#000080\">final</font></b> modifier added to their declarations. <br> <br>\n<!-- tooltip end -->\nUse check boxes in the inspection options below, to define which declarations are to be reported.\n</body>\n</html>\n");
		list = t.split();
		printEach(list);
		assertEquals(2, list.size());
		assertEquals("This inspection reports all fields, methods or classes, found in the specified inspection scope, that may have a <b><font color=\"#000080\">final</font></b> modifier added to their declarations.<br><br><!-- tooltip end -->", list.get(0).toString());
		assertEquals("This inspection reports all fields, methods or classes, found in the specified inspection scope, that may have a <b><font color=\"#000080\">final</font></b> modifier added to their declarations.", list.get(0).trim());
		assertEquals("Use check boxes in the inspection options below, to define which declarations are to be reported.", list.get(1).toString());

		// 開始が table タグ (分割しない動作の確認)
		t = new TranslationString("<table width=\"100%\" border=\"0\" cellpadding=\"5\" cellspacing=\"0\" style=\"border-collapse: collapse\">  <tr>    <td><font face=\"verdana\" size=\"-1\">Along with static text, code and comments, you can also use      predefined variables (listed below) that will then be expanded like macros into the corresponding values.<br>      It is also possible to specify an arbitrary number of custom variables in the format      <b>${&lt;VARIABLE_NAME&gt;}</b>. In this case, before the new      file is created, you will be prompted with a dialog where you can define particular values for all      custom variables.<br>      Using the <b>#parse</b> directive, you can include templates from the <i>Includes</i>      tab, by specifying the full name of the desired template as a parameter in quotation marks.      For example:<br>      <b>#parse(\"File Header.java\")</b>    </font></td>  </tr></table><table width=\"100%\" border=\"0\" cellpadding=\"5\" cellspacing=\"0\" style=\"border-collapse: collapse\">  <tr>    <td colspan=\"3\"><font face=\"verdana\" size=\"-1\">Predefined variables will take the following values:</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${PACKAGE_NAME}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">name of the package in which the new file is created</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${NAME}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">name of the new file specified by you in the <i>New &lt;TEMPLATE_NAME&gt;</i> dialog</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${USER}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current user system login name</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${DATE}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current system date</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${TIME}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current system time</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${YEAR}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current year</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${MONTH}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current month</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${MONTH_NAME_SHORT}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">first 3 letters of the current month name. Example: Jan, Feb, etc.</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${MONTH_NAME_FULL}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">full name of the current month. Example: January, February, etc.</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${DAY}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current day of the month</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${DAY_NAME_SHORT}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">first 3 letters of the current day name. Example: Mon, Tue, etc.</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${DAY_NAME_FULL}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">full name of the current day. Example: Monday, Tuesday, etc.</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${HOUR}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current hour</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${MINUTE}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">current minute</font></td>  </tr>  <tr>    <td valign=\"top\"><nobr><font face=\"verdana\" size=\"-2\"><b>${PROJECT_NAME}</b></font></nobr></td>    <td width=\"10\">&nbsp;</td>    <td width=\"100%\" valign=\"top\"><font face=\"verdana\" size=\"-1\">the name of the current project</font></td>  </tr></table><hr> <font face=\"verdana\" size=\"-1\"><a href='http://velocity.apache.org/engine/devel/user-guide.html#Velocity_Template_Language_VTL:_An_Introduction'>\nApache Velocity</a> template language is used</font>");
		list = t.split();
		printEach(list);
		assertEquals("For example:<br>", list.get(4).toString());
		assertEquals("For example:", list.get(4).trim());
		assertEquals("For example", list.get(4).trimForce());
		assertEquals("Predefined variables will take the following values:", list.get(6).trim());
		assertEquals("<a href='http://velocity.apache.org/engine/devel/user-guide.html#Velocity_Template_Language_VTL:_An_Introduction'> Apache Velocity</a> template language is used", list.get(list.size() - 1).trim());

		// HTML の場合は改行があっても分割する
		t = new TranslationString("<html>\nNo in-line parameter name hints will be shown for methods matching any of these patterns.<br>\nPatterns are matched on fully qualified method name, parameter count and parameter names.\n<ul>\n<li><code>java.lang</code> matches all methods from <em>java.lang</em> package</li>\n<li><code>java.lang.*(*, *)</code> matches all methods from the <em>java.lang</em> package with two parameters</li>\n<li><code>(*info)</code> matches all single parameter methods where the parameter name ends with <em>info</em></li>\n<li><code>(key, value)</code> matches all methods with parameters <em>key</em> and <em>value</em></li>\n<li><code>*.put(key, value)</code> matches all <em>put</em> methods with <em>key</em> and <em>value</em> parameters\n</ul>\n</html>");
		list = t.split();
		printEach(list);
		assertEquals(7, list.size());

		// HTML font タグ分割 (ブロックタグの前の font 要素は次の要素先頭にあることを確認)
		t = new TranslationString("<html>Semantic highlighting<br><font color=gray><sub>Assign each parameter and local variable its<br>own color picked from spectrum below</sub></font></html>");
		list = t.split();
		printEach(list);
		assertEquals("Semantic highlighting<br>", list.get(0).toString());
		assertEquals("Semantic highlighting", list.get(0).trim());
		assertEquals("<font color=gray><sub>Assign each parameter and local variable its<br>own color picked from spectrum below</sub></font>", list.get(1).toString());
		assertEquals("Assign each parameter and local variable its<br>own color picked from spectrum below", list.get(1).trim());

		// head タグに囲まれていない style タグ
		t = new TranslationString("<html><style></style><div>aaa<div x>bbb<div>ccc</div></html>");
		list = t.split();
		printEach(list);
		assertEquals(3, list.size());
		assertEquals("aaa", list.get(0).toString());
		assertEquals("bbb", list.get(1).trim());
		assertEquals("ccc", list.get(2).trim());

		// ! + 改行も分割
		t = new TranslationString("Installation failed with message {0}.\nIt is possible that this issue is resolved by uninstalling an existing version of the apk if it is present, and then re-installing.\n\nWARNING: Uninstalling will remove the application data!\n\nDo you want to uninstall the existing application?");
		list = t.split();
		printEach(list);
		assertEquals(5, list.size());

		// 追加分割正規表現パターン
		t = new TranslationString("aaa<br>bbb");
		list = t.split();
		printEach(list);
		assertNull(list);

		t = new TranslationString("aaa<br>bbb");
		list = t.split("<BR/?>");
		printEach(list);
		assertEquals(2, list.size());
	}
}
