From 9d0f22f9bd8eda5d49e6d6017819800960c72515 Mon Sep 17 00:00:00 2001 From: whistyun Date: Sun, 20 Dec 2020 17:01:34 +0900 Subject: [PATCH 1/6] fix prefix dupplication error When using XmlService.Save, the prefix "p" may be duplicated. --- src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs index 6558504..b12093e 100644 --- a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs +++ b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs @@ -74,8 +74,16 @@ public string AddNamespace (string ns) prefix = String.Empty; else if ((s = GetAcronym (ns)) != null && !l.Any (i => i.Prefix == s)) prefix = s; - else - prefix = sctx.GetPreferredPrefix (ns); + else + { + var idx = 2; + s = sctx.GetPreferredPrefix(ns); + prefix = s; + while (l.Any(i => i.Prefix == prefix)) + { + prefix = s + idx++; + } + } l.Add (new NamespaceDeclaration (ns, prefix)); return prefix; } From 50e31604e357763e32a16750305ad625fc8a960e Mon Sep 17 00:00:00 2001 From: whistyun Date: Tue, 22 Dec 2020 07:56:52 +0900 Subject: [PATCH 2/6] avoid use while --- .../Portable.Xaml/PrefixLookup.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs index b12093e..bee1b70 100644 --- a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs +++ b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs @@ -76,14 +76,20 @@ public string AddNamespace (string ns) prefix = s; else { - var idx = 2; - s = sctx.GetPreferredPrefix(ns); - prefix = s; - while (l.Any(i => i.Prefix == prefix)) - { - prefix = s + idx++; - } - } + s = sctx.GetPreferredPrefix(ns); + if (!l.Any(i => i.Prefix == s)) + prefix = s; + else + { + int checkSuffix(string p) + => !p.StartsWith("p") ? 0 : + int.TryParse(p.Substring(1), out var i) ? i : + 1; + + var idx = l.Max(i => checkSuffix(i.Prefix)) + 1; + prefix = s + idx; + } + } l.Add (new NamespaceDeclaration (ns, prefix)); return prefix; } From 3ba8c6384cc37bc3dac9bd7f4d717d9402c440cb Mon Sep 17 00:00:00 2001 From: whistyun Date: Tue, 22 Dec 2020 10:09:51 +0900 Subject: [PATCH 3/6] add testcase --- src/Test/System.Xaml/XamlXmlWriterTest.cs | 59 ++++++++++++++++++++++- src/Test/XmlFiles/AcronymDuplicate1.xml | 4 ++ src/Test/XmlFiles/AcronymDuplicate2.xml | 5 ++ src/Test/XmlFiles/AcronymDuplicate3.xml | 6 +++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/Test/XmlFiles/AcronymDuplicate1.xml create mode 100644 src/Test/XmlFiles/AcronymDuplicate2.xml create mode 100644 src/Test/XmlFiles/AcronymDuplicate3.xml diff --git a/src/Test/System.Xaml/XamlXmlWriterTest.cs b/src/Test/System.Xaml/XamlXmlWriterTest.cs index 99f6918..e0522f3 100644 --- a/src/Test/System.Xaml/XamlXmlWriterTest.cs +++ b/src/Test/System.Xaml/XamlXmlWriterTest.cs @@ -1,4 +1,4 @@ -// +// // Copyright (C) 2010 Novell Inc. http://novell.com // // Permission is hereby granted, free of charge, to any person obtaining @@ -1281,10 +1281,67 @@ public void Write_ShoudSerializeObjectInCollection() Assert.AreEqual(xaml, actual); } } + + [Test] + public void Write_AcronymDuplicate() + { + var list = new List(); + list.Add(new Acronym.Class1()); + list.Add(new Acronym1.Class1()); + + Assert.AreEqual( + XamlServices.Parse(ReadXml("AcronymDuplicate1.xml")), + XamlServices.Parse(XamlServices.Save(list)), + "#1"); + + list.Add(new Acronym2.Class1()); + + Assert.AreEqual( + XamlServices.Parse(ReadXml("AcronymDuplicate2.xml")), + XamlServices.Parse(XamlServices.Save(list)), + "#2"); + + list.Add(new Acronym3.Class1()); + + Assert.AreEqual( + XamlServices.Parse(ReadXml("AcronymDuplicate3.xml")), + XamlServices.Parse(XamlServices.Save(list)), + "#3"); + } + } public class TestXmlWriterClass1 { public int Foo { get; set; } } + + namespace Acronym + { + public class Class1 { + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + return GetType() == obj.GetType(); + } + + public override int GetHashCode() =>this.GetType().GetHashCode(); + } + } + namespace Acronym1 + { + public class Class1: Acronym.Class1 {} + } + namespace Acronym2 + { + public class Class1: Acronym.Class1 { } + } + namespace Acronym3 + { + public class Class1: Acronym.Class1 { } + } } diff --git a/src/Test/XmlFiles/AcronymDuplicate1.xml b/src/Test/XmlFiles/AcronymDuplicate1.xml new file mode 100644 index 0000000..3836780 --- /dev/null +++ b/src/Test/XmlFiles/AcronymDuplicate1.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Test/XmlFiles/AcronymDuplicate2.xml b/src/Test/XmlFiles/AcronymDuplicate2.xml new file mode 100644 index 0000000..09dc605 --- /dev/null +++ b/src/Test/XmlFiles/AcronymDuplicate2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Test/XmlFiles/AcronymDuplicate3.xml b/src/Test/XmlFiles/AcronymDuplicate3.xml new file mode 100644 index 0000000..f3837e2 --- /dev/null +++ b/src/Test/XmlFiles/AcronymDuplicate3.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 1497a2648ace347c7d17fc833abfa077f3d6d3c1 Mon Sep 17 00:00:00 2001 From: whistyun Date: Tue, 22 Dec 2020 20:53:21 +0900 Subject: [PATCH 4/6] add suffix to acronym, if possible. --- .../Portable.Xaml/PrefixLookup.cs | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs index bee1b70..74e6054 100644 --- a/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs +++ b/src/Portable.Xaml/Portable.Xaml/PrefixLookup.cs @@ -70,30 +70,45 @@ public string AddNamespace (string ns) string prefix, s; if (ns == XamlLanguage.Xaml2006Namespace) prefix = "x"; - else if (!l.Any (i => i.Prefix == String.Empty)) + else if (!AnyHavePrefix(l, String.Empty)) prefix = String.Empty; - else if ((s = GetAcronym (ns)) != null && !l.Any (i => i.Prefix == s)) - prefix = s; - else - { - s = sctx.GetPreferredPrefix(ns); - if (!l.Any(i => i.Prefix == s)) - prefix = s; - else - { - int checkSuffix(string p) - => !p.StartsWith("p") ? 0 : - int.TryParse(p.Substring(1), out var i) ? i : - 1; - - var idx = l.Max(i => checkSuffix(i.Prefix)) + 1; - prefix = s + idx; - } + else + { + s = GetAcronym(ns) ?? sctx.GetPreferredPrefix(ns); + prefix = AnyHavePrefix(l, s) ? MakePrefixAddNumber(l, s) : s; } l.Add (new NamespaceDeclaration (ns, prefix)); return prefix; } + string MakePrefixAddNumber(List namespaces, string prefix) + { + var prefixLen = prefix.Length; + + int max = 0; + for (int i = 0; i < namespaces.Count; i++) + { + var p = namespaces[i].Prefix; + var suffix = !p.StartsWith(prefix) ? 0 : + int.TryParse(p.Substring(prefixLen), out var idx) ? idx : + 0; + max = Math.Max(suffix, max); + } + + return prefix + (max+1); + } + + bool AnyHavePrefix(List namespaces, string prefix) + { + for (int i = 0; i < namespaces.Count; i++) + { + var ns = namespaces[i]; + if (ns.Prefix == prefix) + return true; + } + return false; + } + const string pre = "clr-namespace:"; string GetAcronym (string ns) From 8f63da81b2d4345ba857b1256632e16d4430de72 Mon Sep 17 00:00:00 2001 From: whistyun Date: Tue, 22 Dec 2020 21:23:31 +0900 Subject: [PATCH 5/6] modify testcase more strict. --- src/Test/System.Xaml/XamlXmlWriterTest.cs | 80 ++++++++++++++++++----- src/Test/XmlFiles/AcronymDuplicate1.xml | 4 -- src/Test/XmlFiles/AcronymDuplicate2.xml | 5 -- src/Test/XmlFiles/AcronymDuplicate3.xml | 6 -- 4 files changed, 64 insertions(+), 31 deletions(-) delete mode 100644 src/Test/XmlFiles/AcronymDuplicate1.xml delete mode 100644 src/Test/XmlFiles/AcronymDuplicate2.xml delete mode 100644 src/Test/XmlFiles/AcronymDuplicate3.xml diff --git a/src/Test/System.Xaml/XamlXmlWriterTest.cs b/src/Test/System.Xaml/XamlXmlWriterTest.cs index e0522f3..6b5a4c6 100644 --- a/src/Test/System.Xaml/XamlXmlWriterTest.cs +++ b/src/Test/System.Xaml/XamlXmlWriterTest.cs @@ -1,4 +1,4 @@ -// +// // Copyright (C) 2010 Novell Inc. http://novell.com // // Permission is hereby granted, free of charge, to any person obtaining @@ -27,6 +27,7 @@ using System.Linq; using System.Reflection; using NUnit.Framework; +using System.Xml.Serialization; #if PORTABLE_XAML using Portable.Xaml.Markup; using Portable.Xaml.ComponentModel; @@ -1283,32 +1284,79 @@ public void Write_ShoudSerializeObjectInCollection() } [Test] - public void Write_AcronymDuplicate() + public void Write_AcronymNonDuplicate() + { + var list = new List(); + list.Add(new Acronym.Class1()); + + var genXaml = XamlServices.Save(list); + + // match object + var readList = XamlServices.Parse(genXaml); + Assert.AreEqual(list, readList, "#1"); + + // check namespace + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa=""clr-namespace:Tests.Portable.Xaml.Acronym;assembly="), "#2"); + } + [Test] + public void Write_AcronymDuplicate1() { var list = new List(); list.Add(new Acronym.Class1()); list.Add(new Acronym1.Class1()); - Assert.AreEqual( - XamlServices.Parse(ReadXml("AcronymDuplicate1.xml")), - XamlServices.Parse(XamlServices.Save(list)), - "#1"); + var genXaml = XamlServices.Save(list); + + // match object + var readList = XamlServices.Parse(genXaml); + Assert.AreEqual(list, readList, "#1"); + + // check namespace + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa=""clr-namespace:Tests.Portable.Xaml.Acronym;assembly="), "#2"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa1=""clr-namespace:Tests.Portable.Xaml.Acronym1;assembly="), "#3"); + } + [Test] + public void Write_AcronymDuplicate2() + { + var list = new List(); + list.Add(new Acronym.Class1()); + list.Add(new Acronym1.Class1()); list.Add(new Acronym2.Class1()); - Assert.AreEqual( - XamlServices.Parse(ReadXml("AcronymDuplicate2.xml")), - XamlServices.Parse(XamlServices.Save(list)), - "#2"); + var genXaml = XamlServices.Save(list); - list.Add(new Acronym3.Class1()); + // match object + var readList = XamlServices.Parse(genXaml); + Assert.AreEqual(list, readList, "#1"); - Assert.AreEqual( - XamlServices.Parse(ReadXml("AcronymDuplicate3.xml")), - XamlServices.Parse(XamlServices.Save(list)), - "#3"); + // check namespace + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa=""clr-namespace:Tests.Portable.Xaml.Acronym;assembly="), "#2"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa1=""clr-namespace:Tests.Portable.Xaml.Acronym1;assembly="), "#3"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa2=""clr-namespace:Tests.Portable.Xaml.Acronym2;assembly="), "#4"); } + [Test] + public void Write_AcronymDuplicate3() + { + var list = new List(); + list.Add(new Acronym.Class1()); + list.Add(new Acronym1.Class1()); + list.Add(new Acronym2.Class1()); + list.Add(new Acronym3.Class1()); + + var genXaml = XamlServices.Save(list); + + // match object + var readList = XamlServices.Parse(genXaml); + Assert.AreEqual(list, readList, "#1"); + + // check namespace + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa=""clr-namespace:Tests.Portable.Xaml.Acronym;assembly="), "#2"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa1=""clr-namespace:Tests.Portable.Xaml.Acronym1;assembly="), "#3"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa2=""clr-namespace:Tests.Portable.Xaml.Acronym2;assembly="), "#4"); + Assert.IsTrue(genXaml.Contains(@"xmlns:tpxa3=""clr-namespace:Tests.Portable.Xaml.Acronym3;assembly="), "#5"); + } } public class TestXmlWriterClass1 @@ -1334,7 +1382,7 @@ public override bool Equals(object obj) } namespace Acronym1 { - public class Class1: Acronym.Class1 {} + public class Class1: Acronym.Class1 { } } namespace Acronym2 { diff --git a/src/Test/XmlFiles/AcronymDuplicate1.xml b/src/Test/XmlFiles/AcronymDuplicate1.xml deleted file mode 100644 index 3836780..0000000 --- a/src/Test/XmlFiles/AcronymDuplicate1.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Test/XmlFiles/AcronymDuplicate2.xml b/src/Test/XmlFiles/AcronymDuplicate2.xml deleted file mode 100644 index 09dc605..0000000 --- a/src/Test/XmlFiles/AcronymDuplicate2.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/Test/XmlFiles/AcronymDuplicate3.xml b/src/Test/XmlFiles/AcronymDuplicate3.xml deleted file mode 100644 index f3837e2..0000000 --- a/src/Test/XmlFiles/AcronymDuplicate3.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From d489d5cdcb4f69aa7a4fd3d863bd4437a3abda17 Mon Sep 17 00:00:00 2001 From: whistyun Date: Tue, 22 Dec 2020 22:21:56 +0900 Subject: [PATCH 6/6] add workaround for build --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2f7ce4a..f8985ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,9 @@ jobs: fileName: 'Portable.Xaml.snk' encodedString: ${{ secrets.STRONG_NAME_KEY }} + - name: Clear package cache as a temporary workaround for actions/setup-dotnet#155 + run: dotnet clean && dotnet nuget locals all --clear + - name: Build run: dotnet build ${{ env.PlatformBuildParameters }} ${{ env.BuildParameters }} "/p:AssemblyOriginatorKeyFile=${{ steps.get_strong_name.outputs.filePath }}"