public void Roundtrip_LdmlInvalidStandardCollation()
		{
			using (var environment = new TestEnvironment())
			{
				const string icuRules =
					"&&&B<t<<<T<s<<<S<e<<<E\r\n\t\t\t\t&C<k<<<K<x<<<X<i<<<I\r\n\t\t\t\t&D<q<<<Q<r<<<R\r\n\t\t\t\t&G<o<<<O\r\n\t\t\t\t&W<h<<<H";
				var cd = new IcuRulesCollationDefinition("standard")
				{
					IcuRules = icuRules,
					CollationRules = icuRules,
					IsValid = false
				};

				var wsToLdml = new WritingSystemDefinition("aa", "Latn", "", "");
				wsToLdml.Collations.Add(cd);
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);

				XElement ldmlElem = XElement.Load(environment.FilePath("test.ldml"));
				XElement collationsElem = ldmlElem.Element("collations");
				XElement defaultCollationElem = collationsElem.Element("defaultCollation");
				XElement collationElem = collationsElem.Element("collation");
				Assert.That((string)defaultCollationElem, Is.EqualTo("standard"));
				Assert.That((string)collationElem.Attribute("type"), Is.EqualTo("standard"));
				Assert.That((string)collationElem, Is.EqualTo(icuRules.Replace("\r\n", "\n")));
				// Verify comment written about being unable to parse ICU rule
				const string expectedComment = "'Unable to parse the ICU rules with ICU version'";
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath(string.Format("/ldml/collations/collation/comment()[contains(.,{0})]", expectedComment));

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.Collations.First().ValueEquals(cd));
			}
		}
		public void Roundtrip_LdmlSimpleCollation()
		{
			using (var environment = new TestEnvironment())
			{
				const string simpleRules =
					"\r\n\t\t\t\t\ta/A\r\n\t\t\t\t\tb/B\r\n\t\t\t\t\tt/T\r\n\t\t\t\t\ts/S\r\n\t\t\t\t\tc/C\r\n\t\t\t\t\tk/K\r\n\t\t\t\t\tx/X\r\n\t\t\t\t\ti/I\r\n\t\t\t\t\td/D\r\n\t\t\t\t\tq/Q\r\n\t\t\t\t\tr/R\r\n\t\t\t\t\te/E\r\n\t\t\t\t\tf/F\r\n\t\t\t\t\tg/G\r\n\t\t\t\t\to/O\r\n\t\t\t\t\tj/J\r\n\t\t\t\t\tl/L\r\n\t\t\t\t\tm/M\r\n\t\t\t\t\tn/N\r\n\t\t\t\t\tp/P\r\n\t\t\t\t\tu/U\r\n\t\t\t\t\tv/V\r\n\t\t\t\t\tw/W\r\n\t\t\t\t\th/H\r\n\t\t\t\t\ty/Y\r\n\t\t\t\t\tz/Z\r\n\t\t\t\t";
				const string icuRules =
					"&[before 1] [first regular]  < a\\/A < b\\/B < t\\/T < s\\/S < c\\/C < k\\/K < x\\/X < i\\/I < d\\/D < q\\/Q < r\\/R < e\\/E < f\\/F < g\\/G < o\\/O < j\\/J < l\\/L < m\\/M < n\\/N < p\\/P < u\\/U < v\\/V < w\\/W < h\\/H < y\\/Y < z\\/Z";
				var cd = new SimpleRulesCollationDefinition("standard")
				{
					SimpleRules = simpleRules,
					CollationRules = icuRules,
					IsValid = true
				};
				var wsToLdml = new WritingSystemDefinition("aa", "Latn", "", "");
				wsToLdml.Collations.Add(cd);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				XElement ldmlElem = XElement.Load(environment.FilePath("test.ldml"));
				XElement collationsElem = ldmlElem.Element("collations");
				XElement defaultCollationElem = collationsElem.Element("defaultCollation");
				XElement collationElem = collationsElem.Element("collation");
				XElement crElem = collationElem.Element("cr");
				XElement simpleElem = collationElem.Element("special").Element(Sil + "simple");
				Assert.That((string)defaultCollationElem, Is.EqualTo("standard"));
				Assert.That((string)collationElem.Attribute("type"), Is.EqualTo("standard"));
				Assert.That((string)crElem, Is.EqualTo(icuRules.Replace("\r\n", "\n")));
				Assert.That((string)simpleElem, Is.EqualTo(simpleRules.Replace("\r\n", "\n")));

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);

				Assert.That(wsFromLdml.Collations.First().ValueEquals(cd));
				Assert.That(wsFromLdml.DefaultCollation.ValueEquals(cd));
			}
		}
		public void Migrate_LdmlIsFlexPrivateUseFormatDefaultMigrator_FileIsUpdated()
		{
			using (var environment = new TestEnvironment())
			{
				var originalFilecontent = LdmlContentForTests.Version0("x-en", "Zxxx", "US", "1901-x-audio");
				environment.WriteLdmlFile("test.ldml", originalFilecontent);
				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback, WritingSystemCompatibility.Strict);
				migrator.Migrate();
				AssertThatLdmlMatches("qaa", "Zxxx", "US", "1901-x-en-audio", environment.FilePath("qaa-Zxxx-US-1901-x-en-audio.ldml"));
			}
		}
		public void Roundtrip_LdmlStandardCollation()
		{
			using (var environment = new TestEnvironment())
			{
				const string icuRules =
					"&B<t<<<T<s<<<S<e<<<E\r\n\t\t\t\t&C<k<<<K<x<<<X<i<<<I\r\n\t\t\t\t&D<q<<<Q<r<<<R\r\n\t\t\t\t&G<o<<<O\r\n\t\t\t\t&W<h<<<H";
				var cd = new IcuRulesCollationDefinition("standard")
				{
					IcuRules = icuRules,
					CollationRules = icuRules,
					IsValid = true
				};

				var wsToLdml = new WritingSystemDefinition("aa", "Latn", "", "");
				wsToLdml.Collations.Add(cd);
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);

				XElement ldmlElem = XElement.Load(environment.FilePath("test.ldml"));
				XElement collationsElem = ldmlElem.Element("collations");
				XElement defaultCollationElem = collationsElem.Element("defaultCollation");
				XElement collationElem = collationsElem.Element("collation");
				Assert.That((string)defaultCollationElem, Is.EqualTo("standard"));
				Assert.That((string) collationElem.Attribute("type"), Is.EqualTo("standard"));
				Assert.That((string) collationElem, Is.EqualTo(icuRules.Replace("\r\n", "\n")));
				
				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.Collations.First().ValueEquals(cd));
			}
		}
		public void Write_UnknownKeyboard_NotWrittenToLdml()
		{
			using (var environment = new TestEnvironment())
			{
				var urls = new List<string>
				{
					"http://wirl.scripts.sil.org/keyman",
					"http://scripts.sil.org/cms/scripts/page.php?item_id=keyman9"
				};
				IKeyboardDefinition kbd1 = Keyboard.Controller.CreateKeyboard("Compiled Keyman9", KeyboardFormat.CompiledKeyman, urls);
				IKeyboardDefinition kbd2 = Keyboard.Controller.CreateKeyboard("Unknown System Keyboard", KeyboardFormat.Unknown, urls);

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.KnownKeyboards.Add(kbd1);
				wsToLdml.KnownKeyboards.Add(kbd2);
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath(
						"/ldml/special/sil:external-resources/sil:kbd[@id='Compiled Keyman9' and @type='kmx']/sil:url[text()='http://wirl.scripts.sil.org/keyman']",
						environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath(
						"/ldml/special/sil:external-resources/sil:kbd[@id='Compiled Keyman9' and @type='kmx']/sil:url[text()='http://scripts.sil.org/cms/scripts/page.php?item_id=keyman9']",
						environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasNoMatchForXpath(
						"/ldml/special/sil:external-resources/sil:kbd[@id='Unknown System Keyboard']",
						environment.NamespaceManager);

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.KnownKeyboards.First(), Is.EqualTo(kbd1));
				Assert.That(wsFromLdml.KnownKeyboards.Count, Is.EqualTo(1));
			}
		}
		public void Write_SystemCollationDefinition_NotWrittenToLdml()
		{
			using (var environment = new TestEnvironment())
			{
				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.DefaultCollation = new SystemCollationDefinition { LanguageTag = "en-US" };
				wsToLdml.Collations.Add(new IcuRulesCollationDefinition("standard"));
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath(
						"/ldml/collations/collation[@type='standard']",
						environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasNoMatchForXpath(
						"/ldml/collations/collation[@type='system']",
						environment.NamespaceManager);
			}
		}
		public void Roundtrip_VariantName()
		{
			using (var environment = new TestEnvironment())
			{
				var wsToLdml = new WritingSystemDefinition("en", "Latn", "GB", "x-test")
				{
					VersionNumber = "$Revision$",
					VersionDescription = "Identity version description",
					WindowsLcid = "1036",
					DefaultRegion = "US"
				};
				wsToLdml.Variants[0] = new VariantSubtag(wsToLdml.Variants[0], "test0");
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());

				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/identity/language[@type='en']");
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasNoMatchForXpath("/ldml/identity/script");
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/identity/territory[@type='GB']");
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/identity/variant[@type='x-test']");
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/identity/version[@number='$Revision$' and text()='Identity version description']");
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/identity/special/sil:identity[@windowsLCID='1036' and @defaultRegion='US' and @variantName='test0']", environment.NamespaceManager);

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.VersionNumber, Is.EqualTo("$Revision$"));
				Assert.That(wsFromLdml.VersionDescription, Is.EqualTo("Identity version description"));
				Assert.That(wsFromLdml.LanguageTag, Is.EqualTo("en-GB-x-test"));
				Assert.That(wsFromLdml.WindowsLcid, Is.EqualTo("1036"));
				Assert.That(wsFromLdml.DefaultRegion, Is.EqualTo("US"));
				int index = IetfLanguageTag.GetIndexOfFirstNonCommonPrivateUseVariant(wsFromLdml.Variants);
				Assert.That(index, Is.EqualTo(0));
				Assert.That(wsFromLdml.Variants[index].Name, Is.EqualTo("test0"));
			}
		}
		public void Roundtrip_LdmlFont()
		{
			using (var environment = new TestEnvironment())
			{
				var fd = new FontDefinition("Padauk")
				{
					RelativeSize = 2.1f,
					MinVersion = "3.1.4",
					Features = "order=3 children=2 color=red createDate=1996",
					Language = "en",
					Engines = FontEngines.Graphite | FontEngines.OpenType,
					OpenTypeLanguage = "abcd",
					Roles = FontRoles.Default | FontRoles.Emphasis,
					Subset = "unknown"
				};
				fd.Urls.Add("http://wirl.scripts.sil.org/padauk");
				fd.Urls.Add("http://scripts.sil.org/cms/scripts/page.php?item_id=padauk");

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.Fonts.Add(fd);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/special/sil:external-resources/sil:font[@name='Padauk' and @types='default emphasis' and @size='2.1' and @minversion='3.1.4' and @features='order=3 children=2 color=red createDate=1996' and @lang='en' and @otlang='abcd' and @subset='unknown']/sil:url[text()='http://wirl.scripts.sil.org/padauk']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/special/sil:external-resources/sil:font[@name='Padauk' and @types='default emphasis' and @size='2.1' and @minversion='3.1.4' and @features='order=3 children=2 color=red createDate=1996' and @lang='en' and @otlang='abcd' and @subset='unknown']/sil:url[text()='http://scripts.sil.org/cms/scripts/page.php?item_id=padauk']", environment.NamespaceManager);


				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);

				Assert.That(wsFromLdml.Fonts.First().ValueEquals(fd));
			}
		}
		public void Migrate_DateModified_IsLaterThanBeforeMigration()
		{
			using (var environment = new TestEnvironment())
			{
				environment.WriteLdmlFile(
					"test.ldml",
					LdmlContentForTests.Version0WithAllSortsOfDatathatdoesNotNeedSpecialAttention("", "", "", ""));

				var wsV0 = new WritingSystemDefinitionV0();
				new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0);
				DateTime dateBeforeMigration = wsV0.DateModified;

				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback);
				migrator.Migrate();

				var wsV3 = new WritingSystemDefinition();
				new LdmlDataMapper(new TestWritingSystemFactory()).Read(environment.MappedFilePath("test.ldml"), wsV3);
				DateTime dateAfterMigration = wsV3.DateModified;
				Assert.IsTrue(dateAfterMigration > dateBeforeMigration);
			}
		}
		public void Migrate_OriginalFileContainsNoCollationInfo_StandardCollationInfoIsMigrated()
		{
			using (var environment = new TestEnvironment())
			{
				environment.WriteLdmlFile(
					"test.ldml",
					LdmlContentForTests.Version0WithCollationInfo(WritingSystemDefinitionV0.SortRulesType.DefaultOrdering));
				var wsV0 = new WritingSystemDefinitionV0();
				new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0);

				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback);
				migrator.Migrate();

				var wsV3 = new WritingSystemDefinition();
				new LdmlDataMapper(null).Read(environment.MappedFilePath("test.ldml"), wsV3);
				var cdV3 = (IcuRulesCollationDefinition) wsV3.Collations.First();
				Assert.IsNullOrEmpty(wsV0.SortRules);
				Assert.IsNullOrEmpty(cdV3.CollationRules);
				Assert.That(cdV3.Type, Is.EqualTo("standard"));
			}
		}
		public void Migrate_OriginalFileContainsCustomIcuCollationInfo_CollationInfoIsMigrated()
		{
			using (var environment = new TestEnvironment())
			{
				environment.WriteLdmlFile(
					"test.ldml",
					LdmlContentForTests.Version0WithCollationInfo(WritingSystemDefinitionV0.SortRulesType.CustomICU));
				var wsV0 = new WritingSystemDefinitionV0();
				new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0);

				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback);
				migrator.Migrate();

				var wsV3 = new WritingSystemDefinition();
				new LdmlDataMapper(null).Read(environment.MappedFilePath("test.ldml"), wsV3);
				var cdV3 = (IcuRulesCollationDefinition) wsV3.Collations.First();
				Assert.AreEqual(wsV0.SortRules, cdV3.CollationRules);
			}
		}
		public void Migrate_OriginalFileContainsSystemCollationInfo_CollationInfoIsMigrated()
		{
			using (var environment = new TestEnvironment())
			{
				environment.WriteLdmlFile(
					"test.ldml",
					LdmlContentForTests.Version0WithSystemCollationInfo());
				var wsV0 = new WritingSystemDefinitionV0();
				new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0);

				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback);
				migrator.Migrate();
				var repo = new TestLdmlInFolderWritingSystemRepository(environment.LdmlPath);
				migrator.ResetRemovedProperties(repo);

				WritingSystemDefinition ws = repo.Get("de");
				var scd = new SystemCollationDefinition {LanguageTag = "de"};
				Assert.That(ws.DefaultCollation.ValueEquals(scd), Is.True);
			}
		}
		public void Migrate_OriginalFileContainsCustomIcuCollationInfo_CollationInfoIsMigrated()
		{
			using (var environment = new TestEnvironment())
			{
				environment.WriteLdmlFile(
					"test.ldml",
					LdmlContentForTests.Version0WithCollationInfo(WritingSystemDefinitionV0.SortRulesType.CustomICU));
				var wsV0 = new WritingSystemDefinitionV0();
				new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0);

				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback);
				migrator.Migrate();

				var wsV1 = new WritingSystemDefinitionV1();
				new LdmlAdaptorV1().Read(environment.MappedFilePath("test.ldml"), wsV1);
				Assert.AreEqual(wsV0.SortRules, wsV1.SortRules);
				Assert.AreEqual(Enum.GetName(typeof(WritingSystemDefinitionV0.SortRulesType), wsV0.SortUsing), Enum.GetName(typeof(WritingSystemDefinitionV1.SortRulesType), wsV0.SortUsing));
			}
		}
		public void Roundtrip_LdmlSimpleCollationNeedsCompiling()
		{
			using (var environment = new TestEnvironment())
			{
				const string simpleRules =
					"\r\n\t\t\t\t\t\\!/A\r\n\t\t\t\t\tb/B\r\n\t\t\t\t\tt/T\r\n\t\t\t\t\ts/S\r\n\t\t\t\t\tc/C\r\n\t\t\t\t\tk/K\r\n\t\t\t\t\tx/X\r\n\t\t\t\t\ti/I\r\n\t\t\t\t\td/D\r\n\t\t\t\t\tq/Q\r\n\t\t\t\t\tr/R\r\n\t\t\t\t\te/E\r\n\t\t\t\t\tf/F\r\n\t\t\t\t\tg/G\r\n\t\t\t\t\to/O\r\n\t\t\t\t\tj/J\r\n\t\t\t\t\tl/L\r\n\t\t\t\t\tm/M\r\n\t\t\t\t\tn/N\r\n\t\t\t\t\tp/P\r\n\t\t\t\t\tu/U\r\n\t\t\t\t\tv/V\r\n\t\t\t\t\tw/W\r\n\t\t\t\t\th/H\r\n\t\t\t\t\ty/Y\r\n\t\t\t\t\tz/Z\r\n\t\t\t\t";
				var cd = new SimpleRulesCollationDefinition("standard")
				{
					SimpleRules = simpleRules,
				};
				var wsToLdml = new WritingSystemDefinition("aa", "Latn", "", "");
				wsToLdml.Collations.Add(cd);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				XElement ldmlElem = XElement.Load(environment.FilePath("test.ldml"));
				XElement collationsElem = ldmlElem.Element("collations");
				XElement defaultCollationElem = collationsElem.Element("defaultCollation");
				XElement collationElem = collationsElem.Element("collation");
				XElement specialElem = collationElem.Element("special");
				XElement simpleElem = specialElem.Element(Sil + "simple");
				Assert.That((string)defaultCollationElem, Is.EqualTo("standard"));
				Assert.That((string)collationElem.Attribute("type"), Is.EqualTo("standard"));
				Assert.That((string)specialElem.Attribute(Sil + "needsCompiling"), Is.EqualTo("true"));
				Assert.That((string)simpleElem, Is.EqualTo(simpleRules.Replace("\r\n", "\n")));

				var validatedCd = new SimpleRulesCollationDefinition("standard")
				{
					SimpleRules = simpleRules
				};
				// When the LDML reader parses the invalid rules, it will validate and regenerate icu rules
				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);

				Assert.That(wsFromLdml.Collations.First().ValueEquals(validatedCd));
				Assert.That(wsFromLdml.DefaultCollation.ValueEquals(validatedCd));
			}
		}
		public void Roundtrip_LdmlLayout()
		{
			using (var environment = new TestEnvironment())
			{
				// Write/Read RightToLeftScript is false
				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "")
				{
					RightToLeftScript = false
				};
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/layout/orientation/characterOrder[text()='left-to-right']");

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.RightToLeftScript, Is.False);

				// Write/Read RightToLeftScript is true
				wsToLdml.RightToLeftScript = true;
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasAtLeastOneMatchForXpath("/ldml/layout/orientation/characterOrder[text()='right-to-left']");

				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.RightToLeftScript, Is.True);
			}
		}
		public void Roundtrip_LdmlIcuCollationWithImports()
		{
			using (var environment = new TestEnvironment())
			{
				const string icuRules =
					"&B<t<<<T<s<<<S<e<<<E\n\t\t\t\t&C<k<<<K<x<<<X<i<<<I\n\t\t\t\t&D<q<<<Q<r<<<R\n\t\t\t\t&G<o<<<O\n\t\t\t\t&W<h<<<H";
				var cd = new IcuRulesCollationDefinition("standard")
				{
					Imports = {new IcuCollationImport("my", "standard")},
					CollationRules = icuRules,
					IsValid = true
				};

				var wsToLdml = new WritingSystemDefinition("aa", "Latn", "", "");
				wsToLdml.Collations.Add(cd);

				var wsFactory = new TestWritingSystemFactory {WritingSystems =
				{
					new WritingSystemDefinition("my")
					{
						Collations = {new IcuRulesCollationDefinition("standard") {IcuRules = icuRules, CollationRules = icuRules, IsValid = true}}
					}
				}};
				var ldmlAdaptor = new LdmlDataMapper(wsFactory);
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				XElement ldmlElem = XElement.Load(environment.FilePath("test.ldml"));
				XElement collationsElem = ldmlElem.Element("collations");
				XElement defaultCollationElem = collationsElem.Element("defaultCollation");
				XElement collationElem = collationsElem.Element("collation");
				XElement crElem = collationElem.Element("cr");
				XElement importElem = collationElem.Element("import");
				Assert.That((string) defaultCollationElem, Is.EqualTo("standard"));
				Assert.That((string) collationElem.Attribute("type"), Is.EqualTo("standard"));
				Assert.That(crElem, Is.Null);
				Assert.That((string) importElem.Attribute("source"), Is.EqualTo("my"));
				Assert.That((string) importElem.Attribute("type"), Is.EqualTo("standard"));

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);

				Assert.That(wsFromLdml.Collations.First().ValueEquals(cd));
				Assert.That(wsFromLdml.DefaultCollation.ValueEquals(cd));
			}
		}
		public void Roundtrip_LdmlCharacters()
		{
			using (var environment = new TestEnvironment())
			{
				var index = new CharacterSetDefinition("index");
				for (int i = 'A'; i <= (int) 'Z'; i++)
					index.Characters.Add(((char) i).ToString(CultureInfo.InvariantCulture));
				index.Characters.Add("AZ");

				var main = new CharacterSetDefinition("main");
				for (int i = 'a'; i <= (int) 'z'; i++)
					main.Characters.Add(((char) i).ToString(CultureInfo.InvariantCulture));
				main.Characters.Add("az");

				var footnotes = new CharacterSetDefinition("footnotes") {Characters = {"¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", "¹⁰"}};

				var numeric = new CharacterSetDefinition("numeric") {Characters = {"๐", "๑", "๒", "๓", "๔", "๕", "๖", "๗", "๘", "๙"}};

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.CharacterSets.Add(index);
				wsToLdml.CharacterSets.Add(main);
				wsToLdml.CharacterSets.Add(footnotes);
				wsToLdml.CharacterSets.Add(numeric);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/characters/exemplarCharacters[@type='index' and text()='[A-Z{AZ}]']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/characters/exemplarCharacters[text()='[a-z{az}]']", environment.NamespaceManager);
				// Character set in XPath is escaped differently from the actual file
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/characters/special/sil:exemplarCharacters[@type='footnotes' and text()='[¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ {¹⁰}]']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/numbers/defaultNumberingSystem[text()='standard']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/numbers/numberingSystem[@id='standard' and @type='numeric' and @digits='๐๑๒๓๔๕๖๗๘๙']", environment.NamespaceManager);

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.CharacterSets["index"].ValueEquals(index), Is.True);
				Assert.That(wsFromLdml.CharacterSets["main"].ValueEquals(main), Is.True);
				Assert.That(wsFromLdml.CharacterSets["footnotes"].ValueEquals(footnotes), Is.True);
				Assert.That(wsFromLdml.CharacterSets["numeric"].ValueEquals(numeric), Is.True);
			}
		}
		public void Roundtrip_LdmlSpellChecker()
		{
			using (var environment = new TestEnvironment())
			{
				var scd = new SpellCheckDictionaryDefinition(SpellCheckDictionaryFormat.Hunspell);
				scd.Urls.Add("http://wirl.scripts.sil.org/hunspell");
				scd.Urls.Add("http://scripts.sil.org/cms/scripts/page.php?item_id=hunspell");

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.SpellCheckDictionaries.Add(scd);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/special/sil:external-resources/sil:spellcheck[@type='hunspell']/sil:url[text()='http://wirl.scripts.sil.org/hunspell']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/special/sil:external-resources/sil:spellcheck[@type='hunspell']/sil:url[text()='http://scripts.sil.org/cms/scripts/page.php?item_id=hunspell']", environment.NamespaceManager);


				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);

				Assert.That(wsFromLdml.SpellCheckDictionaries.First().ValueEquals(scd));
			}
		}
		public void Roundtrip_LdmlAlternateCharacters_Ignored()
		{
			// Test when reading LDML that elements with alt attribute are ignored.
			// Because we don't write elements with alt attribute, this test
			// starts by writing a set content
			using (var environment = new TestEnvironment())
			{
				string content =
@"<?xml version='1.0' encoding='utf-8'?>
<ldml>
	<identity>
		<version number='' />
		<language type='en' />
		<script type='Latn' />
	</identity>
	<characters>
		<exemplarCharacters alt='capital'>[A-Z{AZ}]</exemplarCharacters>
		<exemplarCharacters>[a-z{az}]</exemplarCharacters>
	</characters>
</ldml>".Replace("\'", "\"");

				var main = new CharacterSetDefinition("main");
				for (int i = 'a'; i <= (int)'z'; i++)
					main.Characters.Add(((char)i).ToString(CultureInfo.InvariantCulture));
				main.Characters.Add("az");

				File.WriteAllText(environment.FilePath("test.ldml"), content);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.CharacterSets.Count, Is.EqualTo(1));
				Assert.That(wsFromLdml.CharacterSets["main"].ValueEquals(main));

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.CharacterSets.Add(main);

				ldmlAdaptor.Write(environment.FilePath("test2.ldml"), wsToLdml, new MemoryStream(File.ReadAllBytes(environment.FilePath("test.ldml"))));
				AssertThatXmlIn.File(environment.FilePath("test2.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/characters/exemplarCharacters[text()='[a-z{az}]']", environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test2.ldml"))
					.HasAtLeastOneMatchForXpath("/ldml/characters/exemplarCharacters[@alt='capital' and text()='[A-Z{AZ}]']", environment.NamespaceManager);
			}
		}
		public void Write_KeyboardInfoIsOnlyWrittenOnce()
		{
			using (var environment = new TestEnvironment())
			{
				var ws = new WritingSystemDefinition("en-Zxxx-x-audio");
				var keyboard1 = new DefaultKeyboardDefinition("en-US_MyFavoriteKeyboard", "MyFavoriteKeyboard", "MyFavoriteKeyboard", "en-US", true);
				keyboard1.Format = KeyboardFormat.Msklc;
				ws.KnownKeyboards.Add(keyboard1);
				var keyboard2 = new DefaultKeyboardDefinition("en-GB_SusannasFavoriteKeyboard", "SusannasFavoriteKeyboard", "SusannasFavoriteKeyboard", "en-GB", true);
				keyboard2.Format = KeyboardFormat.Msklc;
				ws.KnownKeyboards.Add(keyboard2);

				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());


				ldmlAdaptor.Write(environment.FilePath("test.ldml"), ws, null);

				//read the file and write it out unchanged
				var ws2 = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), ws2);
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), ws2, new MemoryStream(File.ReadAllBytes(environment.FilePath("test.ldml"))));

				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasSpecifiedNumberOfMatchesForXpath("/ldml/special/sil:external-resources/sil:kbd[@id='en-US_MyFavoriteKeyboard' and @type='msklc']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml")).HasSpecifiedNumberOfMatchesForXpath("/ldml/special/sil:external-resources/sil:kbd[@id='en-GB_SusannasFavoriteKeyboard' and @type='msklc']", 1, environment.NamespaceManager);
			}
		}
		public void Roundtrip_LdmlDelimiters()
		{
			using (var environment = new TestEnvironment())
			{
				var mp = new MatchedPair("mpOpen1", "mpClose2", false);
				var pp = new PunctuationPattern("pattern1", PunctuationPatternContext.Medial);
				// Quotation Marks:
				// Level 1 normal quotation marks (quotationStart and quotationEnd)
				// Level 2 normal quotation marks (alternateQuotationStart and alternateQuotationEnd)
				// Level 3 normal quotation marks (special: sil:quotation-marks)
				// Level 1 narrative quotation marks (special: sil:quotation-marks)
				var qm1 = new QuotationMark("\"", "\"", "\"", 1, QuotationMarkingSystemType.Normal);
				var qm2 = new QuotationMark("{", "}", "{", 2, QuotationMarkingSystemType.Normal);
				var qm3 = new QuotationMark("open1", "close2", "cont3", 3, QuotationMarkingSystemType.Normal);
				var qm4 = new QuotationMark("", null, null, 1, QuotationMarkingSystemType.Narrative);

				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.MatchedPairs.Add(mp);
				wsToLdml.PunctuationPatterns.Add(pp);
				wsToLdml.QuotationMarks.Add(qm1);
				wsToLdml.QuotationMarks.Add(qm2);
				wsToLdml.QuotationMarks.Add(qm3);
				wsToLdml.QuotationMarks.Add(qm4);
				wsToLdml.QuotationParagraphContinueType = QuotationParagraphContinueType.Outermost;
	
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:matched-pairs/sil:matched-pair[@open='mpOpen1' and @close='mpClose2' and @paraClose='false']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:punctuation-patterns/sil:punctuation-pattern[@pattern='pattern1' and @context='medial']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/quotationStart[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/quotationEnd[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/alternateQuotationStart[text()='{']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/alternateQuotationEnd[text()='}']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotationContinue[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:alternateQuotationContinue[text()='{']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotation[@open='open1' and @close='close2' and @continue='cont3' and @level='3']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotation[@open and string-length(@open)=0 and @level='1' and @type='narrative']", 1, environment.NamespaceManager);

				var wsFromLdml = new WritingSystemDefinition();
				ldmlAdaptor.Read(environment.FilePath("test.ldml"), wsFromLdml);
				Assert.That(wsFromLdml.MatchedPairs.FirstOrDefault(), Is.EqualTo(mp));
				Assert.That(wsFromLdml.PunctuationPatterns.FirstOrDefault(), Is.EqualTo(pp));
				Assert.That(wsFromLdml.QuotationParagraphContinueType, Is.EqualTo(QuotationParagraphContinueType.Outermost));
				Assert.That(wsFromLdml.QuotationMarks[0], Is.EqualTo(qm1));
				Assert.That(wsFromLdml.QuotationMarks[1], Is.EqualTo(qm2));
				Assert.That(wsFromLdml.QuotationMarks[2], Is.EqualTo(qm3));
				Assert.That(wsFromLdml.QuotationMarks[3], Is.EqualTo(qm4));
			
				// Test rewriting the loaded file while using the original version as a base to make sure 
				// no duplicate elements are created
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsFromLdml, new MemoryStream(File.ReadAllBytes(environment.FilePath("test.ldml"))));
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:matched-pairs/sil:matched-pair[@open='mpOpen1' and @close='mpClose2' and @paraClose='false']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:punctuation-patterns/sil:punctuation-pattern[@pattern='pattern1' and @context='medial']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/quotationStart[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/quotationEnd[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/alternateQuotationStart[text()='{']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/alternateQuotationEnd[text()='}']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotationContinue[text()='\"']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:alternateQuotationContinue[text()='{']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotation[@open='open1' and @close='close2' and @continue='cont3' and @level='3']", 1, environment.NamespaceManager);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasSpecifiedNumberOfMatchesForXpath("/ldml/delimiters/special/sil:quotation-marks/sil:quotation[@open and string-length(@open)=0 and @level='1' and @type='narrative']", 1, environment.NamespaceManager);
			}
		}
		public void Write_NoLdmlCollations_CollationsNotWrittenToLdml()
		{
			using (var environment = new TestEnvironment())
			{
				var wsToLdml = new WritingSystemDefinition("en", "Latn", "", "");
				wsToLdml.DefaultCollation = new SystemCollationDefinition {LanguageTag = "en-US"};
				var ldmlAdaptor = new LdmlDataMapper(new TestWritingSystemFactory());
				ldmlAdaptor.Write(environment.FilePath("test.ldml"), wsToLdml, null);
				AssertThatXmlIn.File(environment.FilePath("test.ldml"))
					.HasNoMatchForXpath(
						"/ldml/collations",
						environment.NamespaceManager);
			}
		}
		public void Migrate_LdmlIsXonlyFlexPrivateUseFormatandMigratorIsToldRoundTrip_FileIsUntouched()
		{
			using (var environment = new TestEnvironment())
			{
				string filePath = environment.FilePath("test.ldml");
				var originalFilecontent = LdmlContentForTests.Version0("x", "Zxxx", "US", "1901-x-audio");
				environment.WriteLdmlFile("test.ldml", originalFilecontent);
				var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback, WritingSystemCompatibility.Flex7V0Compatible);
				migrator.Migrate();
				AssertThatLdmlMatches("x", "Zxxx", "US", "1901-x-audio", filePath);
				Assert.That(File.ReadAllText(filePath), Is.EqualTo(originalFilecontent));
			}
		}