-
Notifications
You must be signed in to change notification settings - Fork 161
Expand file tree
/
Copy pathPackageHelper.cs
More file actions
224 lines (195 loc) · 9.06 KB
/
PackageHelper.cs
File metadata and controls
224 lines (195 loc) · 9.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using NUnit.Common;
namespace NUnit.Engine
{
/// <summary>
/// Extension methods for use with TestPackages
/// </summary>
public static class PackageHelper
{
public static string ToXml(this TestPackage package)
{
var writer = new StringWriter();
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings() { OmitXmlDeclaration = true });
WriteXml(package, xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
return writer.ToString();
}
private static void WriteXml(TestPackage package, XmlWriter xmlWriter)
{
xmlWriter.WriteStartElement("TestPackage");
// Write ID and FullName
xmlWriter.WriteAttributeString("id", package.ID);
if (package.FullName is not null)
xmlWriter.WriteAttributeString("fullname", package.FullName);
// Write Settings
if (package.Settings.Count != 0)
WriteSettings(package.Settings, xmlWriter);
// Write any SubPackages recursively
foreach (TestPackage subPackage in package.SubPackages)
WriteXml(subPackage, xmlWriter);
xmlWriter.WriteEndElement();
}
private static void WriteSettings(PackageSettings packageSettings, XmlWriter xmlWriter)
{
xmlWriter.WriteStartElement("Settings");
foreach (PackageSetting setting in packageSettings)
{
switch (setting.Name)
{
// Some settings require special handling
case nameof(SettingDefinitions.InternalTraceWriter):
// NYI
break;
case nameof(SettingDefinitions.LOAD):
var filters = (string[])setting.Value;
xmlWriter.WriteAttributeString(nameof(SettingDefinitions.LOAD), $"{string.Join(";", filters)}");
break;
case nameof(SettingDefinitions.TestParametersDictionary):
var dict = (IDictionary<string, string>)setting.Value;
xmlWriter.WriteStartAttribute(setting.Name);
// Quick and Dirty code for attribute value containing XML.
xmlWriter.WriteRaw("<parms>");
foreach (var entry in dict)
{
xmlWriter.WriteRaw("<parm ");
// NOTE: Non-XML chars in value will be replaced
xmlWriter.WriteString($"key='{entry.Key}' value='{entry.Value}'");
xmlWriter.WriteRaw(" />");
}
xmlWriter.WriteRaw("</parms>");
xmlWriter.WriteEndAttribute();
break;
default:
object value = setting.Value;
var type = value.GetType();
if (type.IsPrimitive || type == typeof(string))
xmlWriter.WriteAttributeString(setting.Name, Convert.ToString(value));
break;
}
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// Create a new TestPackage from its XML representation
/// </summary>
/// <param name="xml">String holding the XML representation of the package</param>
/// <returns>A TestPackage</returns>
public static TestPackage FromXml(string xml)
{
var doc = new XmlDocument();
doc.LoadXml(xml);
var reader = new StringReader(doc.OuterXml);
var xmlReader = XmlReader.Create(reader);
// The first element must be TestPackage
if (!ReadTestPackageElement())
throw new InvalidOperationException("Invalid TestPackage XML");
return ReadXml(xmlReader);
bool ReadTestPackageElement()
{
while (xmlReader.Read())
if (xmlReader.NodeType == XmlNodeType.Element)
return xmlReader.Name == "TestPackage";
return false;
}
}
private static TestPackage ReadXml(XmlReader xmlReader)
{
var package = new TestPackage();
package.ID = xmlReader.GetAttribute("id").ShouldNotBeNull();
package.FullName = xmlReader.GetAttribute("fullname");
if (!xmlReader.IsEmptyElement)
{
while (xmlReader.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Element:
switch (xmlReader.Name)
{
case "Settings":
package.Settings.ReadSettings(xmlReader);
break;
case "TestPackage":
package.SubPackages.Add(ReadXml(xmlReader));
break;
}
break;
case XmlNodeType.EndElement:
if (xmlReader.Name == "TestPackage")
return package;
else
throw new Exception("Unexpected EndElement: " + xmlReader.Name);
}
}
throw new Exception("Invalid XML: TestPackage Element not terminated.");
}
return package;
}
private static void ReadSettings(this PackageSettings packageSettings, XmlReader xmlReader)
{
while (xmlReader.MoveToNextAttribute())
{
var name = xmlReader.Name;
var value = xmlReader.Value;
var settingDefinition = SettingDefinitions.Lookup(name);
if (settingDefinition is not null) // Known setting name
{
// A few settings require special handling when deserializing
switch (name)
{
case nameof(SettingDefinitions.InternalTraceWriter):
// NYI
break;
case nameof(SettingDefinitions.LOAD):
packageSettings.Add(SettingDefinitions.LOAD.WithValue(value.Split([';'])));
break;
case nameof(SettingDefinitions.TestParametersDictionary):
var doc = new XmlDocument();
doc.LoadXml(value);
var dict = new Dictionary<string, string>();
foreach (XmlNode node in doc.SelectNodes("parms/parm").ShouldNotBeNull())
dict.Add(node.GetAttribute("key").ShouldNotBeNull(), node.GetAttribute("value").ShouldNotBeNull());
packageSettings.Add(SettingDefinitions.TestParametersDictionary.WithValue(dict));
break;
default:
switch (settingDefinition.ValueType)
{
case Type t when t.IsAssignableFrom(typeof(string)):
packageSettings.Add(name, value);
break;
case Type t when t.IsAssignableFrom(typeof(bool)):
packageSettings.Add(name, bool.Parse(value));
break;
case Type t when t.IsAssignableFrom(typeof(int)):
packageSettings.Add(name, int.Parse(value));
break;
default:
// Setting doesn't match the expected type, ignore or throw an exception?
break;
}
break;
}
}
else // Non-standard Setting created by user
{
// We assume that a setting that parses as a bool or an int
// is intended as that type, otherwise we use string.
if (bool.TryParse(value, out var flag))
packageSettings.Add(name, flag);
else if (int.TryParse(value, out var num))
packageSettings.Add(name, num);
else
packageSettings.Add(name, value);
}
}
xmlReader.MoveToElement();
}
}
}