Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a unit test for XmlSerializationHelper.SerializeToString and did minor code cleanup #1371

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions SIL.Core.Tests/Xml/XmlSerializationHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -494,5 +494,67 @@ public void SerializeToFileWithWriteThrough_NullData_DeserializableFileCreated()
RobustFile.Delete(path);
}
}

[Test]
public void SerializeToString_GenericList_SerializedCorrectly()
{
var source = new[] {"List Item 1", "List Item 2", "List Item 3"};
var data = (from s in source
select new XmlTranslation
{Reference = $"MAT {s.Last()}:6", PhraseKey = s, Translation = s.ToLower()}).ToList();
var result = SerializeToString(data, Encoding.UTF8);
var lines = result.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries).ToList();
var i = 0;
Assert.That(lines[i], Does.StartWith("<?xml"));
Assert.That(lines[i], Does.Contain("encoding=\"utf-8\""));
Assert.That(lines[++i].Trim('\t'), Is.EqualTo("<ArrayOfTranslation>"));
var item = 1;
for (++i; i < lines.Count - 1; i += 4, item++)
{
Assert.That(lines[i].Trim('\t'), Is.EqualTo($"<Translation ref=\"MAT {item}:6\">"));
Assert.That(lines[i + 1].Trim('\t'), Is.EqualTo($"<OriginalPhrase>List Item {item}</OriginalPhrase>"));
Assert.That(lines[i + 2].Trim('\t'), Is.EqualTo($"<Translation>list item {item}</Translation>"));
Assert.That(lines[i + 3].Trim('\t'), Is.EqualTo("</Translation>"));
}
Assert.That(lines[i].Trim('\t'), Is.EqualTo("</ArrayOfTranslation>"));
}
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Little class to support XML serialization
/// </summary>
/// ------------------------------------------------------------------------------------
[XmlType("Translation")]
public class XmlTranslation
{
/// --------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the reference.
/// </summary>
/// --------------------------------------------------------------------------------
[XmlAttribute("ref")]
public string Reference { get; set; }
/// --------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the phrase key (typically the text of the question in English).
/// </summary>
/// --------------------------------------------------------------------------------
[XmlElement("OriginalPhrase")]
public string PhraseKey { get; set; }
/// --------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the translation.
/// </summary>
/// --------------------------------------------------------------------------------
public string Translation { get; set; }
/// --------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="XmlTranslation"/> class.
/// </summary>
/// --------------------------------------------------------------------------------
public XmlTranslation()
{
}
}
}
65 changes: 32 additions & 33 deletions SIL.Core/Xml/XmlSerializationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,9 @@ public InternalXmlReader(string filename, bool fKeepWhitespaceInElements) :
/// Gets the namespace URI (as defined in the W3C Namespace specification) of the
/// node on which the reader is positioned.
/// </summary>
/// <value></value>
/// <returns>The namespace URI of the current node; otherwise an empty string.</returns>
/// --------------------------------------------------------------------------------
public override string NamespaceURI
{
get { return string.Empty; }
}
public override string NamespaceURI => string.Empty;

/// --------------------------------------------------------------------------------
/// <summary>
Expand Down Expand Up @@ -132,6 +128,7 @@ public StringWriterWithEncoding(Encoding encoding)
/// Serializes an object to an XML represented in an array of UTF-8 bytes.
/// </summary>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static byte[] SerializeToByteArray<T>(T data)
{
return SerializeToByteArray(data, false);
Expand Down Expand Up @@ -193,8 +190,7 @@ public static string SerializeToString<T>(T data, bool omitXmlDeclaration)
/// ------------------------------------------------------------------------------------
private static string SerializeToString<T>(T data, bool omitXmlDeclaration, Encoding encoding)
{
if (encoding == null)
encoding = Encoding.Unicode;
encoding ??= Encoding.Unicode;
try
{
using (var strWriter = encoding.Equals(Encoding.Unicode) ? new StringWriter() : new StringWriterWithEncoding(encoding))
Expand Down Expand Up @@ -231,31 +227,32 @@ private static string SerializeToString<T>(T data, bool omitXmlDeclaration, Enco
return null;
}
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static bool SerializeToFile<T>(string filename, T data)
{
return SerializeToFile(filename, data, null);
}

/// ------------------------------------------------------------------------------------
[PublicAPI]
public static bool SerializeToFile<T>(string filename, T data, out Exception e)
{
return SerializeToFile(filename, data, null, out e);
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Serializes an object to a the specified file.
/// Serializes an object to the specified file.
/// </summary>
/// ------------------------------------------------------------------------------------
public static bool SerializeToFile<T>(string filename, T data, string rootElementName)
{
Exception e;
return SerializeToFile(filename, data, rootElementName, out e);
return SerializeToFile(filename, data, rootElementName, out _);
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Serializes an object to a the specified file.
/// Serializes an object to the specified file.
/// </summary>
/// ------------------------------------------------------------------------------------
public static bool SerializeToFile<T>(string filename, T data, string rootElementName,
Expand Down Expand Up @@ -331,11 +328,11 @@ public static void SerializeToFileWithWriteThrough<T>(string path, T data,
public static void SerializeToFileWithWriteThrough<T>(string path, T data)
{
// Note: RobustFile.Create() uses FileOptions.WriteThrough which causes the data to still be
// written to the operating system cache but it is immediately flushed. If this doesn't
// address the problem then a more thorough solution that completely bypasses the cache
// is to use the c++ CreateFile() api and pass both FILE_FLAG_NO_BUFFERING and
// FILE_FLAG_WRITE_THROUGH.
// https://docs.microsoft.com/en-us/windows/win32/fileio/file-caching
// written to the operating system cache, but it is immediately flushed. If this doesn't
// address the problem then a more thorough solution that completely bypasses the cache
// is to use the c++ CreateFile() api and pass both FILE_FLAG_NO_BUFFERING and
// FILE_FLAG_WRITE_THROUGH.
// https://docs.microsoft.com/en-us/windows/win32/fileio/file-caching
using (var writer = RobustFile.Create(path))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
Expand Down Expand Up @@ -394,6 +391,7 @@ public static bool Serialize<T>(TextWriter textWriter, T data,
/// assumption is the writer is expecting UTF8 data.
/// </summary>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static bool SerializeDataAndWriteAsNode<T>(XmlWriter writer, T data)
{
string xmlData = SerializeToString(data);
Expand Down Expand Up @@ -427,19 +425,18 @@ public static bool SerializeDataAndWriteAsNode<T>(XmlWriter writer, T data)
/// ------------------------------------------------------------------------------------
public static T DeserializeFromString<T>(string input)
{
Exception e;
return (DeserializeFromString<T>(input, out e));
return (DeserializeFromString<T>(input, out _));
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Deserializes XML from the specified string to an object of the specified type.
/// </summary>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static T DeserializeFromString<T>(string input, bool fKeepWhitespaceInElements)
{
Exception e;
return (DeserializeFromString<T>(input, fKeepWhitespaceInElements, out e));
return (DeserializeFromString<T>(input, fKeepWhitespaceInElements, out _));
}

/// ------------------------------------------------------------------------------------
Expand All @@ -460,13 +457,13 @@ public static T DeserializeFromString<T>(string input, out Exception e)
public static T DeserializeFromString<T>(string input, bool fKeepWhitespaceInElements,
out Exception e)
{
T data = default(T);
T data = default;
e = null;

try
{
if (string.IsNullOrEmpty(input))
return default(T);
return default;

// Whitespace is not allowed before the XML declaration,
// so get rid of any that exists.
Expand Down Expand Up @@ -495,19 +492,18 @@ public static T DeserializeFromString<T>(string input, bool fKeepWhitespaceInEle
/// ------------------------------------------------------------------------------------
public static T DeserializeFromFile<T>(string filename)
{
Exception e;
return DeserializeFromFile<T>(filename, false, out e);
return DeserializeFromFile<T>(filename, false, out _);
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Deserializes XML from the specified file to an object of the specified type.
/// </summary>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static T DeserializeFromFile<T>(string filename, string rootElementName)
{
Exception e;
return DeserializeFromFile<T>(filename, rootElementName, false, out e);
return DeserializeFromFile<T>(filename, rootElementName, false, out _);
}

/// ------------------------------------------------------------------------------------
Expand All @@ -520,10 +516,10 @@ public static T DeserializeFromFile<T>(string filename, string rootElementName)
/// will preserve and return elements that contain only whitespace, otherwise
/// these elements will be ignored during a deserialization.</param>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static T DeserializeFromFile<T>(string filename, bool fKeepWhitespaceInElements)
{
Exception e;
return DeserializeFromFile<T>(filename, fKeepWhitespaceInElements, out e);
return DeserializeFromFile<T>(filename, fKeepWhitespaceInElements, out _);
}

/// ------------------------------------------------------------------------------------
Expand All @@ -538,11 +534,11 @@ public static T DeserializeFromFile<T>(string filename, bool fKeepWhitespaceInEl
/// will preserve and return elements that contain only whitespace, otherwise
/// these elements will be ignored during a deserialization.</param>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static T DeserializeFromFile<T>(string filename, string rootElementName,
bool fKeepWhitespaceInElements)
{
Exception e;
return DeserializeFromFile<T>(filename, rootElementName, fKeepWhitespaceInElements, out e);
return DeserializeFromFile<T>(filename, rootElementName, fKeepWhitespaceInElements, out _);
}

/// ------------------------------------------------------------------------------------
Expand All @@ -569,6 +565,7 @@ public static T DeserializeFromFile<T>(string filename, out Exception e)
/// <param name="e">The exception generated during the deserialization.</param>
/// <returns></returns>
/// ------------------------------------------------------------------------------------
[PublicAPI]
public static T DeserializeFromFile<T>(string filename, string rootElementName,
out Exception e)
{
Expand Down Expand Up @@ -670,9 +667,11 @@ private static T DeserializeInternal<T>(XmlReader reader, string rootElementName
deserializer = new XmlSerializer(typeof(T));
else
{
var rootAttrib = new XmlRootAttribute();
rootAttrib.ElementName = rootElementName;
rootAttrib.IsNullable = true;
var rootAttrib = new XmlRootAttribute
{
ElementName = rootElementName,
IsNullable = true
};
deserializer = new XmlSerializer(typeof(T), rootAttrib);
}

Expand Down
Loading