init
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal class Column
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly string _value;
|
||||
private readonly string _sortString;
|
||||
public const string DELIMITER = "\x1f;;";
|
||||
|
||||
public Column(string name, object value)
|
||||
{
|
||||
_name = name;
|
||||
_value = Convert(value);
|
||||
_sortString = String.Concat(_name.ToLower(), DELIMITER, _value);
|
||||
}
|
||||
|
||||
public static string Convert(object value)
|
||||
{
|
||||
if (value is byte[])
|
||||
{
|
||||
string[] binary = new string[((byte[])value).Length + 1];
|
||||
binary[0] = "0x";
|
||||
for (int i = 1; i < binary.Length; i++)
|
||||
binary[i] = ((byte[])value)[i - 1].ToString("X1");
|
||||
|
||||
return String.Join("", binary);
|
||||
}
|
||||
|
||||
if (value is DateTime)
|
||||
{
|
||||
string time = ((DateTime)value).ToShortDateString() + " ";
|
||||
time += ((DateTime)value).TimeOfDay;
|
||||
return time.TrimEnd('0').TrimEnd(':');
|
||||
}
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get { return _value; }
|
||||
}
|
||||
|
||||
public string SortString
|
||||
{
|
||||
get { return _sortString; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal class Database
|
||||
{
|
||||
private int _tableCount = 0;
|
||||
private int _hashCode = 0;
|
||||
private readonly Dictionary<Table, int> _tables = new Dictionary<Table, int>();
|
||||
|
||||
public int TableCount
|
||||
{
|
||||
get { return _tableCount; }
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<Table, int>> Tables
|
||||
{
|
||||
get { return _tables; }
|
||||
}
|
||||
|
||||
public void AddTable(Table table)
|
||||
{
|
||||
if (_tables.ContainsKey(table))
|
||||
_tables[table]++;
|
||||
else
|
||||
_tables.Add(table, 1);
|
||||
|
||||
_tableCount++;
|
||||
_hashCode = _hashCode + table.GetHashCode();
|
||||
}
|
||||
|
||||
public bool ContainsTable(Table table)
|
||||
{
|
||||
return _tables.ContainsKey(table);
|
||||
}
|
||||
|
||||
public int GetCount(Table table)
|
||||
{
|
||||
return _tables[table];
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
public override bool Equals(object otherObject)
|
||||
{
|
||||
if (!(otherObject is Database))
|
||||
return false;
|
||||
|
||||
Database other = (Database)otherObject;
|
||||
|
||||
if (TableCount != other.TableCount ||
|
||||
GetHashCode() != other.GetHashCode())
|
||||
return false;
|
||||
|
||||
foreach (KeyValuePair<Table, int> pair in _tables)
|
||||
if (!other.ContainsTable(pair.Key) ||
|
||||
other.GetCount(pair.Key) != pair.Value)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Text;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal static class ResultSetParser
|
||||
{
|
||||
private const int NAME = 0;
|
||||
private const int WIDTH = 2;
|
||||
private const int PRECISION = 3;
|
||||
private const int SCALE = 4;
|
||||
private const int TYPE = 24;
|
||||
|
||||
internal static Database Parse(SqlCommand command)
|
||||
{
|
||||
using (SqlDataReader sqlReader = command.ExecuteReader())
|
||||
{
|
||||
Database results = new Database();
|
||||
|
||||
if (!sqlReader.HasRows)
|
||||
return results;
|
||||
|
||||
do
|
||||
{
|
||||
Table table = new Table("Result Set");
|
||||
List<string> fieldNames = SetFields(table, sqlReader.GetSchemaTable());
|
||||
while (sqlReader.Read())
|
||||
{
|
||||
Row row = new Row("datarow");
|
||||
for (int i = 0; i < sqlReader.FieldCount; i++)
|
||||
{
|
||||
object value = sqlReader.GetValue(i);
|
||||
if (!(value is DBNull))
|
||||
row.AddColumn(new Column(fieldNames[i], sqlReader.GetValue(i)));
|
||||
}
|
||||
table.AddRow(row);
|
||||
}
|
||||
results.AddTable(table);
|
||||
} while (sqlReader.NextResult());
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<string> SetFields(Table table, DataTable schema)
|
||||
{
|
||||
List<string> fieldNames = new List<string>();
|
||||
foreach (DataRow dataRow in schema.Rows)
|
||||
{
|
||||
string name = dataRow[NAME].ToString();
|
||||
string type = dataRow[TYPE].ToString().ToLower();
|
||||
string precision = dataRow[PRECISION].ToString();
|
||||
string scale = dataRow[SCALE].ToString();
|
||||
string width = dataRow[WIDTH].ToString();
|
||||
|
||||
StringBuilder typeString = new StringBuilder(type);
|
||||
|
||||
if (type.Equals("decimal") || type.Equals("numeric"))
|
||||
{
|
||||
typeString.Append("(");
|
||||
typeString.Append(precision);
|
||||
typeString.Append(",");
|
||||
typeString.Append(scale);
|
||||
typeString.Append(")");
|
||||
}
|
||||
else if (type.Contains("char") || type.Contains("binary"))
|
||||
{
|
||||
if (int.Parse(width) > 8000)
|
||||
width = "max";
|
||||
|
||||
typeString.Append("(");
|
||||
typeString.Append(width);
|
||||
typeString.Append(")");
|
||||
}
|
||||
|
||||
fieldNames.Add(name);
|
||||
table.AddField(name, typeString.ToString());
|
||||
}
|
||||
return fieldNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal class Row
|
||||
{
|
||||
private readonly string _type;
|
||||
private readonly List<Column> _columns = new List<Column>();
|
||||
private string _keyString;
|
||||
private bool _keyValid = false;
|
||||
public const string DELIMITER = "\x1e;;";
|
||||
|
||||
public Row(string type)
|
||||
{
|
||||
_type = type.ToLower();
|
||||
}
|
||||
|
||||
public void AddColumn(Column column)
|
||||
{
|
||||
_columns.Add(column);
|
||||
_keyValid = false;
|
||||
}
|
||||
|
||||
public string KeyString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_keyValid)
|
||||
{
|
||||
string[] keyString = new string[_columns.Count + 1];
|
||||
keyString[0] = _type;
|
||||
for (int i = 1; i < keyString.Length; i++)
|
||||
keyString[i] = _columns[i - 1].SortString;
|
||||
|
||||
_keyString = String.Join(DELIMITER, keyString);
|
||||
_keyValid = true;
|
||||
}
|
||||
return _keyString;
|
||||
}
|
||||
}
|
||||
|
||||
public int ColumnCount
|
||||
{
|
||||
get { return _columns.Count; }
|
||||
}
|
||||
}
|
||||
}
|
||||
117
DataPRO/UnitTest/DatabaseUnitTesting/Utilities/Results/Table.cs
Normal file
117
DataPRO/UnitTest/DatabaseUnitTesting/Utilities/Results/Table.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal class Table
|
||||
{
|
||||
private readonly string _name1;
|
||||
private readonly string _name2;
|
||||
private Row _schema = new Row("schema");
|
||||
private readonly Dictionary<string, int> rows = new Dictionary<string, int>();
|
||||
|
||||
private int _hashCode;
|
||||
private int _rowCount;
|
||||
private int _fieldCount;
|
||||
|
||||
public Table(string name1) : this(name1, String.Empty)
|
||||
{ }
|
||||
|
||||
public Table(string name1, string name2)
|
||||
{
|
||||
_name1 = name1.ToLower();
|
||||
_name2 = name2.ToLower();
|
||||
}
|
||||
|
||||
|
||||
public override bool Equals(object otherObject)
|
||||
{
|
||||
if (!(otherObject is Table))
|
||||
return false;
|
||||
|
||||
Table other = (Table)otherObject;
|
||||
|
||||
if (GetHashCode() != other.GetHashCode())
|
||||
return false;
|
||||
|
||||
if (RowCount != other.RowCount ||
|
||||
FieldCount != other.FieldCount ||
|
||||
!Schema.KeyString.Equals(other.Schema.KeyString))
|
||||
return false;
|
||||
|
||||
int otherCount;
|
||||
|
||||
foreach (string row in rows.Keys)
|
||||
if (!other.LookupRow(row, out otherCount) ||
|
||||
otherCount != rows[row])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
public string Name1
|
||||
{
|
||||
get { return _name1; }
|
||||
}
|
||||
|
||||
public string Name2
|
||||
{
|
||||
get { return _name2; }
|
||||
}
|
||||
|
||||
public void AddRow(Row row)
|
||||
{
|
||||
string key = row.KeyString;
|
||||
if (rows.ContainsKey(key))
|
||||
rows[key]++;
|
||||
else
|
||||
rows.Add(key, 1);
|
||||
|
||||
_rowCount = _rowCount + 1;
|
||||
_hashCode = _hashCode + key.GetHashCode();
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, int>> Rows
|
||||
{
|
||||
get { return rows; }
|
||||
}
|
||||
|
||||
public int RowCount
|
||||
{
|
||||
get { return _rowCount; }
|
||||
}
|
||||
|
||||
public int FieldCount
|
||||
{
|
||||
get { return _fieldCount; }
|
||||
}
|
||||
|
||||
public Row Schema
|
||||
{
|
||||
get { return _schema; }
|
||||
set
|
||||
{
|
||||
_schema = value;
|
||||
_fieldCount = _schema.ColumnCount;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddField(string name, string type)
|
||||
{
|
||||
Column c = new Column(name, type.ToLower());
|
||||
_schema.AddColumn(c);
|
||||
_fieldCount++;
|
||||
// _hashCode = _hashCode + c.SortString.GetHashCode();
|
||||
}
|
||||
|
||||
public bool LookupRow(string key, out int other)
|
||||
{
|
||||
return rows.TryGetValue(key, out other);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace DatabaseUnitTesting.Utilities.Results
|
||||
{
|
||||
internal static class XmlFileAdapter
|
||||
{
|
||||
private const string LEFT = "\0L;;";
|
||||
private const string RIGHT = "\0R;;";
|
||||
|
||||
internal static Database Read(string filename)
|
||||
{
|
||||
XmlDocument document = new XmlDocument();
|
||||
Database database = new Database();
|
||||
|
||||
document.Load(filename);
|
||||
XmlNode xmlRoot = document.LastChild;
|
||||
|
||||
if (xmlRoot == null)
|
||||
return database;
|
||||
|
||||
foreach (Table diff in ReadTables(xmlRoot))
|
||||
database.AddTable(diff);
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
internal static List<Table> ReadTables(XmlNode xmlRoot)
|
||||
{
|
||||
List<Table> tableDiffs = new List<Table>();
|
||||
for (XmlNode xmlObject = xmlRoot.FirstChild; xmlObject != null; xmlObject = xmlObject.NextSibling)
|
||||
{
|
||||
XmlAttribute name1Attribute = xmlObject.Attributes["name1"];
|
||||
XmlAttribute name2Attribute = xmlObject.Attributes["name2"];
|
||||
|
||||
if (name1Attribute == null || name2Attribute == null)
|
||||
throw new XmlSyntaxException("Tables must have name1 and name2 attributes");
|
||||
|
||||
Table tableDiff = new Table(name1Attribute.Value, name2Attribute.Value);
|
||||
|
||||
Row schema = new Row("schema");
|
||||
ReadColumns(xmlObject.FirstChild, schema);
|
||||
|
||||
tableDiff.Schema = schema;
|
||||
|
||||
foreach (Row row in ReadRows(xmlObject))
|
||||
{
|
||||
tableDiff.AddRow(row);
|
||||
}
|
||||
|
||||
tableDiffs.Add(tableDiff);
|
||||
}
|
||||
return tableDiffs;
|
||||
}
|
||||
|
||||
internal static List<Row> ReadRows(XmlNode xmlTable)
|
||||
{
|
||||
List<Row> rowDiffs = new List<Row>();
|
||||
for (XmlNode xmlRow = xmlTable.FirstChild.NextSibling; xmlRow != null; xmlRow = xmlRow.NextSibling)
|
||||
{
|
||||
XmlAttribute typeAttribute = xmlRow.Attributes["type"];
|
||||
|
||||
if (typeAttribute == null)
|
||||
throw new XmlSyntaxException("Row does not have a 'type' attribute");
|
||||
|
||||
Row row = new Row(typeAttribute.Value);
|
||||
ReadColumns(xmlRow, row);
|
||||
rowDiffs.Add(row);
|
||||
}
|
||||
return rowDiffs;
|
||||
}
|
||||
|
||||
internal static void ReadColumns(XmlNode xmlRow, Row row)
|
||||
{
|
||||
for (XmlNode column = xmlRow.FirstChild; column != null; column = column.NextSibling)
|
||||
{
|
||||
XmlAttribute nameAttribute = column.Attributes["name"];
|
||||
|
||||
if (nameAttribute == null)
|
||||
throw new XmlSyntaxException("Fields and Keys must have 'name' attributes");
|
||||
|
||||
string name = nameAttribute.Value.ToLower();
|
||||
|
||||
if (column.Name.ToLower().Equals("column"))
|
||||
{
|
||||
XmlAttribute valueAttribute = column.Attributes["value"];
|
||||
if (valueAttribute == null)
|
||||
throw new XmlSyntaxException("Columns must have 'value' attribute");
|
||||
|
||||
row.AddColumn(new Column(name, valueAttribute.Value.Replace(LEFT, "<").Replace(RIGHT, ">")));
|
||||
}
|
||||
else
|
||||
throw new XmlSyntaxException("Rows may only contain 'column' children");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Write(string filename, Database diffs)
|
||||
{
|
||||
using (XmlTextWriter writer = new XmlTextWriter(filename, Encoding.UTF8))
|
||||
{
|
||||
writer.Formatting = Formatting.Indented;
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("results");
|
||||
|
||||
foreach (KeyValuePair<Table, int> table in diffs.Tables)
|
||||
for (int i = 0; i < table.Value; i++)
|
||||
WriteTable(writer, table.Key);
|
||||
|
||||
writer.WriteEndDocument();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteTable(XmlTextWriter writer, Table tableDiff)
|
||||
{
|
||||
writer.WriteStartElement("object");
|
||||
|
||||
writer.WriteAttributeString("name1", tableDiff.Name1);
|
||||
writer.WriteAttributeString("name2", tableDiff.Name2);
|
||||
|
||||
|
||||
WriteRow(writer, tableDiff.Schema.KeyString);
|
||||
|
||||
foreach (KeyValuePair<string, int> row in tableDiff.Rows)
|
||||
{
|
||||
for (int i = 0; i < row.Value; i++)
|
||||
WriteRow(writer, row.Key);
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
internal static void WriteRow(XmlTextWriter writer, string rowDiff)
|
||||
{
|
||||
writer.WriteStartElement("row");
|
||||
string[] columns = rowDiff.Split(new string[] { Row.DELIMITER }, StringSplitOptions.None);
|
||||
|
||||
writer.WriteAttributeString("type", columns[0]);
|
||||
for (int i = 1; i < columns.Length; i++)
|
||||
WriteColumn(writer, columns[i]);
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
internal static void WriteColumn(XmlTextWriter writer, string column)
|
||||
{
|
||||
string[] definition = column.Split(new string[] { Column.DELIMITER }, StringSplitOptions.None);
|
||||
|
||||
writer.WriteStartElement("column");
|
||||
writer.WriteAttributeString("name", definition[0]);
|
||||
writer.WriteAttributeString("value", definition[1].Replace("<", LEFT).Replace(">", RIGHT));
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user