7
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
using System.Collections;
33
using System.Xml.Serialization;
34
using System.Globalization;
35
using MonoDevelop.Core;
37
namespace MonoDevelop.NUnit
39
public class XmlResultsStore: IResultsStore
41
Hashtable fileCache = new Hashtable ();
44
Hashtable cachedRootList = new Hashtable ();
46
static XmlSerializer serializer = new XmlSerializer (typeof(TestRecord));
48
public XmlResultsStore (string directory, string storeId)
51
this.storeId = storeId;
54
public void RegisterResult (string configuration, UnitTest test, UnitTestResult result)
56
string aname = test.StoreRelativeName;
58
TestRecord root = GetRootRecord (configuration, result.TestDate);
60
root = new TestRecord ();
61
fileCache [GetRootFileName (configuration, result.TestDate)] = root;
64
TestRecord record = root;
66
if (aname.Length > 0) {
67
string[] path = test.StoreRelativeName.Split ('.');
68
foreach (string p in path) {
69
TestRecord ctr = record.Tests != null ? record.Tests [p] : null;
71
ctr = new TestRecord ();
73
if (record.Tests == null)
74
record.Tests = new TestRecordCollection ();
75
record.Tests.Add (ctr);
81
if (record.Results == null)
82
record.Results = new UnitTestResultCollection ();
83
record.Results.Add (result);
86
public UnitTestResult GetNextResult (string configuration, UnitTest test, DateTime date)
88
DateTime currentDate = date;
89
TestRecord root = GetRootRecord (configuration, currentDate);
91
root = GetNextRootRecord (configuration, ref currentDate);
93
while (root != null) {
94
TestRecord tr = FindRecord (root, test.StoreRelativeName);
95
if (tr != null && tr.Results != null) {
96
foreach (UnitTestResult res in tr.Results) {
97
if (res.TestDate > date)
101
root = GetNextRootRecord (configuration, ref currentDate);
106
public UnitTestResult GetPreviousResult (string configuration, UnitTest test, DateTime date)
108
DateTime currentDate = date;
109
TestRecord root = GetRootRecord (configuration, currentDate);
111
root = GetPreviousRootRecord (configuration, ref currentDate);
113
while (root != null) {
114
TestRecord tr = FindRecord (root, test.StoreRelativeName);
115
if (tr != null && tr.Results != null) {
116
for (int n = tr.Results.Count - 1; n >= 0; n--) {
117
UnitTestResult res = (UnitTestResult) tr.Results [n];
118
if (res.TestDate < date)
122
root = GetPreviousRootRecord (configuration, ref currentDate);
127
public UnitTestResult GetLastResult (string configuration, UnitTest test, DateTime date)
129
return GetPreviousResult (configuration, test, date.AddTicks (1));
132
public UnitTestResult[] GetResults (string configuration, UnitTest test, DateTime startDate, DateTime endDate)
134
ArrayList list = new ArrayList ();
135
DateTime firstDay = new DateTime (startDate.Year, startDate.Month, startDate.Day);
137
DateTime[] dates = GetStoreDates (configuration);
139
foreach (DateTime date in dates) {
145
TestRecord root = GetRootRecord (configuration, date);
146
if (root == null) continue;
148
TestRecord tr = FindRecord (root, test.StoreRelativeName);
149
if (tr != null && tr.Results != null) {
150
foreach (UnitTestResult res in tr.Results) {
151
if (res.TestDate >= startDate && res.TestDate <= endDate)
157
return (UnitTestResult[]) list.ToArray (typeof(UnitTestResult));
160
public UnitTestResult[] GetResultsToDate (string configuration, UnitTest test, DateTime endDate, int count)
162
ArrayList list = new ArrayList ();
163
DateTime[] dates = GetStoreDates (configuration);
165
for (int n = dates.Length - 1; n >= 0 && list.Count < count; n--) {
166
if (dates [n] > endDate)
169
TestRecord root = GetRootRecord (configuration, dates [n]);
170
if (root == null) continue;
172
TestRecord tr = FindRecord (root, test.StoreRelativeName);
173
if (tr != null && tr.Results != null) {
174
for (int m = tr.Results.Count - 1; m >= 0 && list.Count < count; m--) {
175
UnitTestResult res = (UnitTestResult) tr.Results [m];
176
if (res.TestDate <= endDate)
182
UnitTestResult[] array = (UnitTestResult[]) list.ToArray (typeof(UnitTestResult));
183
Array.Reverse (array);
189
if (!Directory.Exists (basePath))
190
Directory.CreateDirectory (basePath);
192
foreach (DictionaryEntry entry in fileCache) {
193
TestRecord record = (TestRecord) entry.Value;
194
if (!record.Modified)
197
string file = Path.Combine (basePath, (string)entry.Key);
198
StreamWriter writer = new StreamWriter (file);
200
serializer.Serialize (writer, record);
204
record.Modified = false;
206
cachedRootList.Clear ();
209
TestRecord FindRecord (TestRecord root, string aname)
211
if (aname.Length == 0)
214
string[] path = aname.Split ('.');
215
TestRecord tr = root;
216
foreach (string p in path) {
217
if (tr.Tests == null)
227
TestRecord GetRootRecord (string configuration, DateTime date)
229
string file = GetRootFileName (configuration, date);
230
TestRecord res = (TestRecord) fileCache [file];
235
filePath = Path.Combine (basePath, file);
236
} catch (Exception) {
239
if (!File.Exists (filePath))
242
StreamReader s = new StreamReader (filePath);
244
res = (TestRecord) serializer.Deserialize (s);
245
} catch (Exception ex) {
246
LoggingService.LogError (ex.ToString ());
251
fileCache [file] = res;
255
TestRecord GetNextRootRecord (string configuration, ref DateTime date)
257
DateTime[] dates = GetStoreDates (configuration);
258
foreach (DateTime d in dates) {
261
return GetRootRecord (configuration, d);
267
TestRecord GetPreviousRootRecord (string configuration, ref DateTime date)
269
date = new DateTime (date.Year, date.Month, date.Day);
270
DateTime[] dates = GetStoreDates (configuration);
271
for (int n = dates.Length - 1; n >= 0; n--) {
272
if (dates [n] < date) {
274
return GetRootRecord (configuration, dates [n]);
280
string GetRootFileName (string configuration, DateTime date)
282
// Filter out all invalid path characters in the file name (see: Bug 3023 - Running NUnit tests throws ArgumentException: Illegal Characters in path)
283
var filteredConfiguration = new string (configuration.Where (c => !Path.GetInvalidPathChars ().Any (i => c == i)).ToArray ());
284
return storeId + "-" + filteredConfiguration + "-" + date.ToString ("yyyy-MM-dd", CultureInfo.InvariantCulture) + ".xml";
287
DateTime ParseFileNameDate (string configuration, string fileName)
289
fileName = Path.GetFileNameWithoutExtension (fileName);
290
fileName = fileName.Substring (storeId.Length + configuration.Length + 2);
291
return DateTime.ParseExact (fileName, "yyyy-MM-dd", CultureInfo.InvariantCulture);
294
DateTime[] GetStoreDates (string configuration)
296
if (!Directory.Exists (basePath))
297
return new DateTime [0];
299
DateTime[] res = (DateTime[]) cachedRootList [configuration];
303
ArrayList dates = new ArrayList ();
304
foreach (string file in Directory.GetFiles (basePath, storeId + "-" + configuration + "-*")) {
306
DateTime t = ParseFileNameDate (configuration, Path.GetFileName (file));
310
res = (DateTime[]) dates.ToArray (typeof(DateTime));
311
cachedRootList [configuration] = res;
316
public class TestRecord
319
UnitTestResultCollection results;
320
TestRecordCollection tests;
321
internal bool Modified;
326
set { name = value; }
329
public UnitTestResultCollection Results {
330
get { return results; }
331
set { results = value; }
334
public TestRecordCollection Tests {
335
get { return tests; }
336
set { tests = value; }
340
public class TestRecordCollection: CollectionBase
342
public new TestRecord this [int n] {
343
get { return (TestRecord) ((IList)this) [n]; }
346
public new TestRecord this [string name] {
348
for (int n=0; n<List.Count; n++)
349
if (((TestRecord)List [n]).Name == name)
350
return (TestRecord) List [n];
355
public void Add (TestRecord test)
357
((IList)this).Add (test);
361
public class UnitTestResultCollection: CollectionBase
363
public new UnitTestResult this [int n] {
364
get { return (UnitTestResult) ((IList)this) [n]; }
367
public void Add (UnitTestResult test)
369
((IList)this).Add (test);