* Apply R# clean-up for reliability - Migrate to NUnit4 Assert.That - Update dependencise versions - Fix LangVersion to 9.0 (until net core migration) - Reformat code - Apply 'var' style (easier for refactoring) - Remove redundant parentheses - Add braces on every condition blocks (1 line) - Uses new null checking patterns - Uses AutoProperties when possible - Uses string scalar type instead of class - Clean usings - Add .orig files in git ignore - Rename some properties to respect defined conventions and US format definition - ID -> Id - BPM -> Bpm - Finish -> End * Update R# settings according to the clean-up made
573 lines
18 KiB
C#
573 lines
18 KiB
C#
#region license
|
|
// This file is part of Vocaluxe.
|
|
//
|
|
// Vocaluxe is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Vocaluxe is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Xml.Serialization;
|
|
using NUnit.Framework;
|
|
using Vocaluxe.Base;
|
|
using VocaluxeLib;
|
|
using VocaluxeLib.Xml;
|
|
|
|
namespace Tests.VocaluxeLib.XML
|
|
{
|
|
[TestFixture]
|
|
public class CXmlSerializerTest
|
|
{
|
|
private const string _Head = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
|
|
private const string _Empty = _Head + @"<root />";
|
|
|
|
#region Tests
|
|
[Test]
|
|
public void TestBasic()
|
|
{
|
|
const string s = @"<root>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>";
|
|
const string sUnordered = @"<root>
|
|
<D>4</D>
|
|
<I>1</I>
|
|
<F>3</F>
|
|
<S>2</S>
|
|
</root>";
|
|
var xml = new CXmlDeserializer();
|
|
var foo = xml.DeserializeString<SBasic>(s);
|
|
Assert.That(foo.I, Is.EqualTo(1));
|
|
Assert.That(foo.S, Is.EqualTo("2"));
|
|
Assert.That(foo.F, Is.EqualTo(3).Within(0.0001));
|
|
Assert.That(foo.D, Is.EqualTo(4).Within(0.0001));
|
|
foo = xml.DeserializeString<SBasic>(sUnordered);
|
|
Assert.That(foo.I, Is.EqualTo(1));
|
|
Assert.That(foo.S, Is.EqualTo("2"));
|
|
Assert.That(foo.F, Is.EqualTo(3).Within(0.0001));
|
|
Assert.That(foo.D, Is.EqualTo(4).Within(0.0001));
|
|
}
|
|
|
|
[Test]
|
|
public void TestMissingXmlElement()
|
|
{
|
|
var s = new string[]
|
|
{
|
|
@"<root>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>",
|
|
@"<root>
|
|
<I>1</I>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>",
|
|
@"<root>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
</root>"
|
|
};
|
|
foreach (var s1 in s)
|
|
{
|
|
_AssertXmlSerializeFailWithMissingElement<SBasic, CXmlMissingElementException>(s1);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TestMissingStructElement()
|
|
{
|
|
var s = new string[]
|
|
{
|
|
@"<root>
|
|
<Foo>1</Foo>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>",
|
|
@"<root>
|
|
<I>1</I>
|
|
<Foo>1</Foo>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>",
|
|
@"<root>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
<Foo>1</Foo>
|
|
</root>"
|
|
};
|
|
foreach (var s1 in s)
|
|
{
|
|
var sTmp = s1;
|
|
_AssertXmlSerializeFailWithMissingElement<SBasic, CXmlException>(sTmp);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TestBasicSerialization()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
</root>";
|
|
_AssertSerDeserMatch<SBasic>(s);
|
|
}
|
|
|
|
private readonly string[] _XmlList =
|
|
{
|
|
_Head + @"<root>
|
|
<Ints>
|
|
<Entry>
|
|
<I>1</I>
|
|
</Entry>
|
|
<Entry>
|
|
<I>1</I>
|
|
</Entry>
|
|
</Ints>
|
|
</root>",
|
|
_Head + @"<root>
|
|
<Ints>
|
|
</Ints>
|
|
</root>",
|
|
_Head + @"<root>
|
|
<Ints />
|
|
</root>"
|
|
};
|
|
|
|
[Test]
|
|
public void TestList()
|
|
{
|
|
var xml = new CXmlDeserializer();
|
|
var ser = new CXmlSerializer();
|
|
var foo = xml.DeserializeString<SList>(_XmlList[0]);
|
|
Assert.That(foo.Ints, Has.Count.EqualTo(2), "Deserialization failed");
|
|
Assert.That(foo.Ints[0].I, Is.EqualTo(1), "Deserialization failed");
|
|
Assert.That(foo.Ints[1].I, Is.EqualTo(1), "Deserialization failed");
|
|
var res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlList[0]), "Serialization failed");
|
|
foo = xml.DeserializeString<SList>(_XmlList[1]);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization2 failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(_XmlList[2], Is.EqualTo(res), "Serialization2 failed");
|
|
foo = xml.DeserializeString<SList>(_XmlList[2]);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization2 failed");
|
|
_AssertSerDeserMatch<SList>(_XmlList[2]);
|
|
res = ser.Serialize(foo);
|
|
Assert.That(_XmlList[2], Is.EqualTo(res), "Serialization2 failed");
|
|
_AssertXmlSerializeFailWithMissingElement<SList, CXmlMissingElementException>(_Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void TestArray()
|
|
{
|
|
var xml = new CXmlDeserializer();
|
|
var ser = new CXmlSerializer();
|
|
var foo = xml.DeserializeString<SArray>(_XmlList[0]);
|
|
Assert.That(foo.Ints, Has.Length.EqualTo(2), "Deserialization failed");
|
|
Assert.That(foo.Ints[0].I, Is.EqualTo(1), "Deserialization failed");
|
|
Assert.That(foo.Ints[1].I, Is.EqualTo(1), "Deserialization failed");
|
|
var res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlList[0]), "Serialization failed");
|
|
foo = xml.DeserializeString<SArray>(_XmlList[1]);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization2 failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(_XmlList[2], Is.EqualTo(res), "Serialization2 failed");
|
|
foo = xml.DeserializeString<SArray>(_XmlList[2]);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization2 failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(_XmlList[2], Is.EqualTo(res), "Serialization2 failed");
|
|
_AssertXmlSerializeFailWithMissingElement<SArray, CXmlMissingElementException>(_Empty);
|
|
}
|
|
|
|
private const string _XmlListEmb = _Head + @"<root>
|
|
<I>2</I>
|
|
<Entry>
|
|
<I>1</I>
|
|
</Entry>
|
|
<J>3</J>
|
|
</root>";
|
|
private const string _XmlListEmb2 = _Head + @"<root>
|
|
<I>2</I>
|
|
<Entry>
|
|
<I>1</I>
|
|
</Entry>
|
|
<Entry>
|
|
<I>2</I>
|
|
</Entry>
|
|
<J>3</J>
|
|
</root>";
|
|
private const string _XmlListEmb3 = _Head + @"<root>
|
|
<I>2</I>
|
|
<J>3</J>
|
|
</root>";
|
|
private const string _XmlListEmb4 = _Head + @"<root>
|
|
<I>2</I>
|
|
<Entry />
|
|
<J>3</J>
|
|
</root>";
|
|
|
|
[Test]
|
|
public void TestListEmbedded()
|
|
{
|
|
var xml = new CXmlDeserializer();
|
|
var ser = new CXmlSerializer();
|
|
var foo = xml.DeserializeString<SListEmb>(_XmlListEmb);
|
|
Assert.That(foo.Ints, Has.Count.EqualTo(1), "Deserialization failed");
|
|
Assert.That(foo.Ints[0].I, Is.EqualTo(1), "Deserialization failed");
|
|
var res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb), "Serialization failed");
|
|
foo = xml.DeserializeString<SListEmb>(_XmlListEmb2);
|
|
Assert.That(foo.Ints, Has.Count.EqualTo(2), "Deserialization failed");
|
|
Assert.That(foo.Ints[1].I, Is.EqualTo(2) , "Deserialization failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb2), "Serialization failed");
|
|
foo = xml.DeserializeString<SListEmb>(_XmlListEmb3);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb3), "Serialization failed");
|
|
ser = new CXmlSerializer(true);
|
|
foo.Ints.Clear();
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb4), "Serialization failed");
|
|
_AssertXmlSerializeFailWithMissingElement<SListEmb, CXmlMissingElementException>(_Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void TestArrayEmbedded()
|
|
{
|
|
var xml = new CXmlDeserializer();
|
|
var ser = new CXmlSerializer();
|
|
var foo = xml.DeserializeString<SArrayEmb>(_XmlListEmb);
|
|
Assert.That(foo.Ints, Has.Length.EqualTo(1), "Deserialization failed");
|
|
Assert.That(foo.Ints[0].I, Is.EqualTo(1), "Deserialization failed");
|
|
var res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb), "Serialization failed");
|
|
foo = xml.DeserializeString<SArrayEmb>(_XmlListEmb2);
|
|
Assert.That(foo.Ints, Has.Length.EqualTo(2), "Deserialization failed");
|
|
Assert.That(foo.Ints[1].I, Is.EqualTo(2), "Deserialization failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb2), "Serialization failed");
|
|
foo = xml.DeserializeString<SArrayEmb>(_XmlListEmb3);
|
|
Assert.That(foo.Ints, Is.Empty, "Deserialization failed");
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb3), "Serialization failed");
|
|
ser = new CXmlSerializer(true);
|
|
foo.Ints = Array.Empty<SEntry>();
|
|
res = ser.Serialize(foo);
|
|
Assert.That(res, Is.EqualTo(_XmlListEmb4), "Serialization failed");
|
|
_AssertXmlSerializeFailWithMissingElement<SArrayEmb, CXmlMissingElementException>(_Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void TestProperty()
|
|
{
|
|
const string xmlString = _Head + @"<root>
|
|
<Public>2</Public>
|
|
<Auto>3</Auto>
|
|
</root>";
|
|
var foo = _AssertSerDeserMatch<SProperty>(xmlString);
|
|
Assert.That(foo.Private, Is.EqualTo(3));
|
|
Assert.That(foo.Auto, Is.EqualTo(3));
|
|
}
|
|
|
|
[Test]
|
|
public void TestByteArray()
|
|
{
|
|
const string xmlString = _Head + @"<root>
|
|
<B>MTMzNw==</B>
|
|
</root>";
|
|
_AssertSerDeserMatch<SBytes>(xmlString);
|
|
}
|
|
|
|
private const string _XmlIgnore = _Head + @"<root>
|
|
<J>2</J>
|
|
</root>";
|
|
private const string _XmlIgnore2 = _Head + @"<root>
|
|
<I>2</I>
|
|
<J>2</J>
|
|
</root>";
|
|
|
|
[Test]
|
|
public void TestIgnore()
|
|
{
|
|
_AssertSerDeserMatch<SIgnore>(_XmlIgnore);
|
|
_AssertXmlSerializeFailWithMissingElement<SIgnore, CXmlException>(_XmlIgnore2);
|
|
}
|
|
|
|
[Test]
|
|
public void TestExisting()
|
|
{
|
|
var foo = new SIgnore { I = 1 };
|
|
var xml = new CXmlDeserializer();
|
|
var ser = new CXmlSerializer();
|
|
var bar = xml.DeserializeString(_XmlIgnore, foo);
|
|
Assert.That(bar.I, Is.EqualTo(1));
|
|
Assert.That(ser.Serialize(bar), Is.EqualTo(_XmlIgnore));
|
|
|
|
var foo2 = new CIgnore { I = 1 };
|
|
var bar2 = xml.DeserializeString(_XmlIgnore, foo2);
|
|
Assert.That(bar2.I, Is.EqualTo(1));
|
|
Assert.That(bar2.J, Is.EqualTo(foo2.J), "Original classes should be modified by the deserialization");
|
|
Assert.That(ser.Serialize(bar2), Is.EqualTo(_XmlIgnore));
|
|
}
|
|
|
|
[Test]
|
|
public void TestOnlyList()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<String>2</String>
|
|
<String>3</String>
|
|
</root>";
|
|
_AssertSerDeserMatch<List<string>>(s);
|
|
}
|
|
|
|
[Test]
|
|
public void TestOnlyDict()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<String name=""val1"">2</String>
|
|
<String name=""val2"">3</String>
|
|
</root>";
|
|
_AssertSerDeserMatch<Dictionary<string, string>>(s);
|
|
}
|
|
|
|
[Test]
|
|
public void TestDefaultValues()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<I>1</I>
|
|
<S>2</S>
|
|
<F>3</F>
|
|
<D>4</D>
|
|
<Sub>
|
|
<I>22</I>
|
|
</Sub>
|
|
</root>";
|
|
_AssertSerDeserMatch<SDefault>(s);
|
|
var xml = new CXmlDeserializer(new CXmlErrorHandler(exception => { }));
|
|
var foo = xml.DeserializeString<SDefault>(@"<root />");
|
|
Assert.That(foo.I, Is.EqualTo(1337));
|
|
Assert.That(foo.F, Is.Null);
|
|
Assert.That(foo.S, Is.EqualTo("Foo"));
|
|
Assert.That(foo.D, Is.EqualTo(666));
|
|
Assert.That(foo.Sub.I, Is.EqualTo(111));
|
|
var newXml = new CXmlSerializer().Serialize(foo);
|
|
Assert.That(newXml, Is.EqualTo(_Head + @"<root>
|
|
<Sub />
|
|
</root>"));
|
|
}
|
|
|
|
[Test]
|
|
public void TestEscapedValues()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<S>Foo\'Bar</S>
|
|
<Sub>
|
|
<S>Foo\'Bar</S>
|
|
</Sub>
|
|
</root>";
|
|
_AssertSerDeserMatch<SUnescaping>(s);
|
|
var xml = new CXmlDeserializer(new CXmlErrorHandler(exception => { }));
|
|
var foo = xml.DeserializeString<SUnescaping>(@"<root />");
|
|
Assert.That(foo.S, Is.EqualTo("Foo\'Bar"));
|
|
Assert.That(foo.Sub.S, Is.EqualTo("Foo\'Bar"));
|
|
}
|
|
|
|
[Test]
|
|
public void TestUnescapedValues()
|
|
{
|
|
const string s = _Head + @"<root>
|
|
<S>Foo\'Bar</S>
|
|
<Sub>
|
|
<S>Foo\'Bar</S>
|
|
</Sub>
|
|
</root>";
|
|
_AssertSerDeserMatch<SUnescaping>(s);
|
|
var xml = new CXmlDeserializer(new CXmlErrorHandler(exception => { }), true);
|
|
var foo = xml.DeserializeString<SUnescaping>(@"<root />");
|
|
Assert.That(foo.S, Is.EqualTo("Foo'Bar"));
|
|
Assert.That(foo.Sub.S, Is.EqualTo("Foo'Bar"));
|
|
}
|
|
|
|
[Test]
|
|
public void TestRealFiles(
|
|
[Values(typeof(SThemeCover), typeof(CConfig.SConfig), /*typeof(SThemeScreen),*/ typeof(SDefaultFonts), typeof(SSkin), typeof(STheme),
|
|
typeof(Dictionary<string, string>))]
|
|
Type type)
|
|
{
|
|
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "VocaluxeLib", "XML", "TestFiles");
|
|
|
|
var xmlPath = Path.Combine(filePath, type.Name + ".xml");
|
|
var deser = new CXmlDeserializer();
|
|
|
|
var foo = deser.Deserialize(xmlPath, Activator.CreateInstance(type));
|
|
|
|
Assert.That(foo, Is.InstanceOf(type), "Wrong type with " + type.Name);
|
|
var ser = new CXmlSerializer(type == typeof(CConfig.SConfig));
|
|
var newXml = ser.Serialize(foo, type == typeof(Dictionary<string, string>) ? "resources" : null);
|
|
// Typename will be uppercase but input is lowercase
|
|
newXml = newXml.Replace("<String", "<string").Replace("</String", "</string");
|
|
var oldXml = File.ReadAllText(xmlPath);
|
|
// Trim trailing whitespace/newlines
|
|
oldXml = oldXml.TrimEnd('\r', '\n', ' ', '\t');
|
|
newXml = newXml.TrimEnd('\r', '\n', ' ', '\t');
|
|
Assert.That(newXml, Is.EqualTo(oldXml), "Reconstructed XML has differences.");
|
|
}
|
|
#endregion
|
|
|
|
#region Helper
|
|
#pragma warning disable 649
|
|
#pragma warning disable 169
|
|
private struct SBasic
|
|
{
|
|
public int I;
|
|
public string S;
|
|
public float F;
|
|
public double D;
|
|
}
|
|
|
|
[XmlType("Entry")]
|
|
private struct SEntry
|
|
{
|
|
public int I;
|
|
}
|
|
|
|
private struct SList
|
|
{
|
|
[XmlArray]
|
|
public List<SEntry> Ints;
|
|
}
|
|
|
|
private struct SArray
|
|
{
|
|
[XmlArray]
|
|
public SEntry[] Ints;
|
|
}
|
|
|
|
private struct SListEmb
|
|
{
|
|
public int I;
|
|
[XmlElement("Entry")]
|
|
public List<SEntry> Ints;
|
|
public int J;
|
|
}
|
|
|
|
private struct SArrayEmb
|
|
{
|
|
public int I;
|
|
[XmlElement("Entry")]
|
|
public SEntry[] Ints;
|
|
public int J;
|
|
}
|
|
|
|
private struct SProperty
|
|
{
|
|
[XmlIgnore]
|
|
public int Private;
|
|
// ReSharper disable UnusedMember.Local
|
|
public int Public
|
|
{
|
|
get { return Private - 1; }
|
|
set { Private = value + 1; }
|
|
}
|
|
// ReSharper restore UnusedMember.Local
|
|
// ReSharper disable UnusedAutoPropertyAccessor.Local
|
|
public int Auto { get; set; }
|
|
// ReSharper restore UnusedAutoPropertyAccessor.Local
|
|
}
|
|
|
|
private struct SBytes
|
|
{
|
|
public byte[] B;
|
|
}
|
|
|
|
private struct SIgnore
|
|
{
|
|
[XmlIgnore]
|
|
public int I;
|
|
public int J;
|
|
}
|
|
|
|
private class CIgnore
|
|
{
|
|
[XmlIgnore]
|
|
public int I;
|
|
public int J;
|
|
}
|
|
|
|
private struct SDefaultSub
|
|
{
|
|
[DefaultValue(111)]
|
|
public int I;
|
|
}
|
|
|
|
private struct SDefault
|
|
{
|
|
[DefaultValue(1337)]
|
|
public int I;
|
|
[DefaultValue("Foo")]
|
|
public string S;
|
|
public float? F;
|
|
[DefaultValue(666.0)]
|
|
public double D;
|
|
public SDefaultSub Sub;
|
|
}
|
|
|
|
private struct SUnescaping
|
|
{
|
|
[DefaultValue("Foo\'Bar")]
|
|
public string S;
|
|
public SUnescapingSub Sub;
|
|
}
|
|
|
|
private struct SUnescapingSub
|
|
{
|
|
[DefaultValue("Foo\'Bar")]
|
|
public string S;
|
|
}
|
|
|
|
#pragma warning restore 169
|
|
#pragma warning restore 649
|
|
|
|
private static void _AssertXmlSerializeFailWithMissingElement<TSerializeType, TXmlException>(string xmlString)
|
|
where TSerializeType : new()
|
|
where TXmlException : CXmlException
|
|
{
|
|
var deserializer = new CXmlDeserializer();
|
|
Assert.Throws<TXmlException>(new Action(() => deserializer.DeserializeString<TSerializeType>(xmlString)));
|
|
}
|
|
|
|
private static T _AssertSerDeserMatch<T>(string xmlString) where T : new()
|
|
{
|
|
var deserializer = new CXmlDeserializer();
|
|
var serializer = new CXmlSerializer();
|
|
var foo = deserializer.DeserializeString<T>(xmlString);
|
|
var xmlNew = serializer.Serialize(foo);
|
|
Assert.That(xmlString, Is.EqualTo(xmlNew));
|
|
return foo;
|
|
}
|
|
#endregion
|
|
}
|
|
} |