diff --git a/.github/workflows/github-actions-release.yml b/.github/workflows/github-actions-release.yml
index 9a2fb15..667c94c 100644
--- a/.github/workflows/github-actions-release.yml
+++ b/.github/workflows/github-actions-release.yml
@@ -7,7 +7,7 @@ on:
type: string
description: The version of the library
required: true
- default: 2.1.0
+ default: 2.2.0
VersionSuffix:
type: string
description: The version suffix of the library (for example rc.1)
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 2689e88..26a5ca9 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -11,6 +11,14 @@
README.md
MIT
+ 2.2.0
+ - Add SqlServerDatabase.ClearDataAsync() method.
+ - Add SqlServer.CreateDatabase() method to create database from an Entity Framework DbContext.
+ - Add SqlServer.CreateEmptyDatabaseAsync() method.
+ - Add SqlServer.DeleteDatabaseAsync() method.
+ - Add SqlServerDatabase.ExecuteScriptAsync() method.
+ - Add SqlServerDatabase.InsertIntoAsync() method.
+
2.1.0
- PosInformatique.Testing.Databases.SqlServer target the .NET Standard 2.0 platform.
- PosInformatique.Testing.Databases.SqlServer.Dac target the .NET Core 6.0 and .NET Framework 4.6.2
diff --git a/src/Testing.Databases.SqlServer.EntityFramework/EntityFrameworkSqlServerExtensions.cs b/src/Testing.Databases.SqlServer.EntityFramework/EntityFrameworkSqlServerExtensions.cs
index 73eb0d3..ace72cc 100644
--- a/src/Testing.Databases.SqlServer.EntityFramework/EntityFrameworkSqlServerExtensions.cs
+++ b/src/Testing.Databases.SqlServer.EntityFramework/EntityFrameworkSqlServerExtensions.cs
@@ -15,13 +15,33 @@ namespace PosInformatique.Testing.Databases.SqlServer
public static class EntityFrameworkSqlServerExtensions
{
///
- /// Deploy a database using a DACPAC file.
+ /// Creates a database using the specified Entity Framework .
///
- /// If a database already exists, it will be deleted.
+ /// If the database already exists, it will be deleted.
/// instance where the database will be created.
/// Name of the database to create.
/// which represents the database to create.
/// An instance of the which represents the deployed database.
+ public static SqlServerDatabase CreateDatabase(this SqlServer server, string name, DbContext context)
+ {
+ var database = server.GetDatabase(name);
+
+ context.Database.SetConnectionString(database.ConnectionString);
+
+ context.Database.EnsureDeleted();
+ context.Database.EnsureCreated();
+
+ return database;
+ }
+
+ ///
+ /// Creates a database using the specified Entity Framework .
+ ///
+ /// If the database already exists, it will be deleted.
+ /// instance where the database will be created.
+ /// Name of the database to create.
+ /// which represents the database to create.
+ /// A which represents the asynchronous operation and contains an instance of the that represents the deployed database.
public static async Task CreateDatabaseAsync(this SqlServer server, string name, DbContext context)
{
var database = server.GetDatabase(name);
diff --git a/src/Testing.Databases.SqlServer/Comparer/ISqlObjectDifferencesVisitor.cs b/src/Testing.Databases.SqlServer/Comparer/ISqlObjectDifferencesVisitor.cs
index f912b8f..7987556 100644
--- a/src/Testing.Databases.SqlServer/Comparer/ISqlObjectDifferencesVisitor.cs
+++ b/src/Testing.Databases.SqlServer/Comparer/ISqlObjectDifferencesVisitor.cs
@@ -11,6 +11,8 @@ internal interface ISqlObjectDifferencesVisitor
void Visit(SqlObjectDifferences differences)
where TSqlObject : SqlObject;
+ void Visit(SqlColumnDifferences differences);
+
void Visit(SqlForeignKeyDifferences differences);
void Visit(SqlIndexDifferences differences);
diff --git a/src/Testing.Databases.SqlServer/Comparer/SqlColumnDifferences.cs b/src/Testing.Databases.SqlServer/Comparer/SqlColumnDifferences.cs
new file mode 100644
index 0000000..7090e53
--- /dev/null
+++ b/src/Testing.Databases.SqlServer/Comparer/SqlColumnDifferences.cs
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Testing.Databases
+{
+ ///
+ /// Represents the differences of a between two databases.
+ ///
+ public class SqlColumnDifferences : SqlObjectDifferences
+ {
+ internal SqlColumnDifferences(
+ SqlColumn? source,
+ SqlColumn? target,
+ SqlObjectDifferenceType type,
+ IReadOnlyList? properties,
+ SqlObjectDifferences? defaultConstraint)
+ : base(source, target, type, properties)
+ {
+ this.DefaultConstraint = defaultConstraint;
+ }
+
+ internal SqlColumnDifferences(
+ SqlObjectDifferences differences)
+ : this(differences.Source, differences.Target, differences.Type, differences.Properties, null)
+ {
+ }
+
+ ///
+ /// Gets the difference of the columns in the foreign key compared.
+ ///
+ public SqlObjectDifferences? DefaultConstraint { get; }
+
+ internal override void Accept(ISqlObjectDifferencesVisitor visitor)
+ {
+ visitor.Visit(this);
+ }
+ }
+}
diff --git a/src/Testing.Databases.SqlServer/Comparer/SqlDatabaseComparisonResultsTextGenerator.cs b/src/Testing.Databases.SqlServer/Comparer/SqlDatabaseComparisonResultsTextGenerator.cs
index b41b17c..f237194 100644
--- a/src/Testing.Databases.SqlServer/Comparer/SqlDatabaseComparisonResultsTextGenerator.cs
+++ b/src/Testing.Databases.SqlServer/Comparer/SqlDatabaseComparisonResultsTextGenerator.cs
@@ -64,6 +64,13 @@ public void Visit(SqlObjectDifferences differences)
}
}
+ public void Visit(SqlColumnDifferences differences)
+ {
+ this.Visit(differences);
+
+ this.Generate(differences.DefaultConstraint, "Default constraint");
+ }
+
public void Visit(SqlForeignKeyDifferences differences)
{
this.WriteProperties(differences.Properties);
@@ -98,13 +105,7 @@ public void Visit(SqlTableDifferences differences)
this.Generate(differences.Indexes, "Indexes");
- if (differences.PrimaryKey is not null)
- {
- this.Indent();
- this.WriteLine($"------ Primary key ------");
- differences.PrimaryKey.Accept(this);
- this.Unindent();
- }
+ this.Generate(differences.PrimaryKey, "Primary key");
this.Generate(differences.Triggers, "Triggers");
@@ -121,6 +122,17 @@ public void Visit(SqlUniqueConstraintDifferences differences)
this.Generate(differences.Columns, "Columns");
}
+ private void Generate(SqlObjectDifferences? difference, string typeName)
+ where TSqlObject : SqlObject
+ {
+ if (difference is null)
+ {
+ return;
+ }
+
+ this.Generate([difference], typeName);
+ }
+
private void Generate(IEnumerable> differences, string typeName)
where TSqlObject : SqlObject
{
diff --git a/src/Testing.Databases.SqlServer/Comparer/SqlObjectComparer.cs b/src/Testing.Databases.SqlServer/Comparer/SqlObjectComparer.cs
index 31b2ccf..35abcf8 100644
--- a/src/Testing.Databases.SqlServer/Comparer/SqlObjectComparer.cs
+++ b/src/Testing.Databases.SqlServer/Comparer/SqlObjectComparer.cs
@@ -26,20 +26,11 @@ public static IList> Compare(IReadO
var keyValue = keySelector(targetObject);
var sourceObject = Find(source, keySelector, keyValue);
- if (sourceObject is null)
- {
- // Missing in the source.
- differences.Add(new SqlObjectDifferences(null, targetObject, SqlObjectDifferenceType.MissingInSource, null));
- }
- else
- {
- // Compare the object using visitor pattern.
- var difference = Compare(sourceObject, targetObject);
+ var difference = Compare(sourceObject, targetObject);
- if (difference is not null)
- {
- differences.Add(difference);
- }
+ if (difference is not null)
+ {
+ differences.Add(difference);
}
}
@@ -61,7 +52,7 @@ public static IList> Compare(IReadO
public static IList Compare(IReadOnlyList source, IReadOnlyList target)
{
- return Compare(source, target, t => t.Name, diff => new SqlTableDifferences(diff) { PrimaryKey = null });
+ return Compare(source, target, t => t.Name, diff => new SqlTableDifferences(diff));
}
public SqlObjectDifferences? Visit(SqlCheckConstraint checkConstraint)
@@ -73,8 +64,10 @@ public static IList Compare(IReadOnlyList source,
public SqlObjectDifferences? Visit(SqlColumn column)
{
- return this.CreateDifferences(
- column,
+ var sourceColumn = (SqlColumn)this.source;
+
+ // Compare the properties
+ var differenceProperties = GetPropertyDifferences(
this.CompareProperty(column, t => t.Position, nameof(column.Position)),
this.CompareProperty(column, t => t.MaxLength, nameof(column.MaxLength)),
this.CompareProperty(column, t => t.Precision, nameof(column.Precision)),
@@ -84,6 +77,24 @@ public static IList Compare(IReadOnlyList source,
this.CompareProperty(column, t => t.CollationName, nameof(column.CollationName)),
this.CompareProperty(column, t => t.IsComputed, nameof(column.IsComputed)),
this.CompareProperty(column, t => TsqlCodeHelper.RemoveNotUsefulCharacters(t.ComputedExpression), nameof(column.ComputedExpression), t => t.ComputedExpression));
+
+ // Compare the default constraint
+ var defaultConstraintDifference = Compare(sourceColumn.DefaultConstraint, column.DefaultConstraint);
+
+ if (differenceProperties.Count > 0 || defaultConstraintDifference != null)
+ {
+ return new SqlColumnDifferences((SqlColumn)this.source, column, SqlObjectDifferenceType.Different, differenceProperties, defaultConstraintDifference);
+ }
+
+ return null;
+ }
+
+ public SqlObjectDifferences? Visit(SqlDefaultConstraint defaultConstraint)
+ {
+ return this.CreateDifferences(
+ defaultConstraint,
+ this.CompareProperty(defaultConstraint, df => df.Name, nameof(defaultConstraint.Name)),
+ this.CompareProperty(defaultConstraint, df => TsqlCodeHelper.RemoveNotUsefulCharacters(df.Expression), nameof(defaultConstraint.Expression), df => df.Expression));
}
public SqlObjectDifferences? Visit(SqlForeignKey foreignKey)
@@ -191,7 +202,7 @@ public static IList Compare(IReadOnlyList source,
var checkConstraintDifferences = Compare(sourceTable.CheckConstraints, table.CheckConstraints, tr => tr.Name);
// Compare the columns
- var columnsDifferences = Compare(sourceTable.Columns, table.Columns, c => c.Name);
+ var columnsDifferences = Compare(sourceTable.Columns, table.Columns, c => c.Name, diff => new SqlColumnDifferences(diff));
// Compare the foreign keys
var foreignKeysDifferences = Compare(sourceTable.ForeignKeys, table.ForeignKeys, fk => fk.Name, diff => new SqlForeignKeyDifferences(diff));
@@ -200,7 +211,7 @@ public static IList Compare(IReadOnlyList source,
var indexesDifferences = Compare(sourceTable.Indexes, table.Indexes, i => i.Name, diff => new SqlIndexDifferences(diff));
// Compare the primary key
- var primaryKeyDifferences = (SqlPrimaryKeyDifferences?)Compare(CreateArray(sourceTable.PrimaryKey), CreateArray(table.PrimaryKey), pk => pk.Name).SingleOrDefault();
+ var primaryKeyDifferences = (SqlPrimaryKeyDifferences?)Compare(sourceTable.PrimaryKey, table.PrimaryKey);
// Compare the triggers
var triggersDifferences = Compare(sourceTable.Triggers, table.Triggers, tr => tr.Name);
@@ -262,9 +273,26 @@ public static IList Compare(IReadOnlyList source,
this.CompareProperty(view, v => TsqlCodeHelper.RemoveNotUsefulCharacters(v.Code), nameof(view.Code), v => v.Code));
}
- private static SqlObjectDifferences? Compare(TSqlObject source, TSqlObject target)
+ private static SqlObjectDifferences? Compare(TSqlObject? source, TSqlObject? target)
where TSqlObject : SqlObject
{
+ if (source is null)
+ {
+ if (target is null)
+ {
+ return null;
+ }
+
+ return new SqlObjectDifferences(null, target, SqlObjectDifferenceType.MissingInSource, null);
+ }
+ else
+ {
+ if (target is null)
+ {
+ return new SqlObjectDifferences(source, null, SqlObjectDifferenceType.MissingInTarget, null);
+ }
+ }
+
var visitor = new SqlObjectComparer(source);
return (SqlObjectDifferences?)target.Accept(visitor);
@@ -303,17 +331,6 @@ private static IReadOnlyList GetPropertyDifferences
return objects.SingleOrDefault(o => Equals(keySelector(o), value));
}
- private static T[] CreateArray(T? value)
- where T : class
- {
- if (value is null)
- {
- return [];
- }
-
- return [value];
- }
-
private SqlObjectPropertyDifference? CompareProperty(TSqlObject target, Func propertyValueForComparison, string name, Func? propertyValueToDisplay = null)
where TSqlObject : SqlObject
{
diff --git a/src/Testing.Databases.SqlServer/Comparer/SqlPrimaryKeyDifferences.cs b/src/Testing.Databases.SqlServer/Comparer/SqlPrimaryKeyDifferences.cs
index 4225313..f114647 100644
--- a/src/Testing.Databases.SqlServer/Comparer/SqlPrimaryKeyDifferences.cs
+++ b/src/Testing.Databases.SqlServer/Comparer/SqlPrimaryKeyDifferences.cs
@@ -24,6 +24,12 @@ internal SqlPrimaryKeyDifferences(
this.Columns = new ReadOnlyCollection>(columns);
}
+ internal SqlPrimaryKeyDifferences(
+ SqlObjectDifferences differences)
+ : this(differences.Source, differences.Target, differences.Type, differences.Properties, [])
+ {
+ }
+
///
/// Gets the difference of the columns in the primary key compared.
///
diff --git a/src/Testing.Databases.SqlServer/Comparer/SqlTableDifferences.cs b/src/Testing.Databases.SqlServer/Comparer/SqlTableDifferences.cs
index 02dad79..2b7a1ee 100644
--- a/src/Testing.Databases.SqlServer/Comparer/SqlTableDifferences.cs
+++ b/src/Testing.Databases.SqlServer/Comparer/SqlTableDifferences.cs
@@ -18,7 +18,7 @@ internal SqlTableDifferences(
SqlTable? target,
SqlObjectDifferenceType type,
IReadOnlyList? properties,
- IList> columns,
+ IList columns,
IList> triggers,
IList> checkConstraints,
IList indexes,
@@ -26,7 +26,7 @@ internal SqlTableDifferences(
IList uniqueConstraints)
: base(source, target, type, properties)
{
- this.Columns = new ReadOnlyCollection>(columns);
+ this.Columns = new ReadOnlyCollection(columns);
this.Triggers = new ReadOnlyCollection>(triggers);
this.CheckConstraints = new ReadOnlyCollection>(checkConstraints);
this.Indexes = new ReadOnlyCollection(indexes);
@@ -48,7 +48,7 @@ internal SqlTableDifferences(
///
/// Gets the columns differences between the two SQL tables.
///
- public ReadOnlyCollection> Columns { get; }
+ public ReadOnlyCollection Columns { get; }
///
/// Gets the indexes differences between the two SQL tables.
diff --git a/src/Testing.Databases.SqlServer/ObjectModel/ISqlObjectVisitor.cs b/src/Testing.Databases.SqlServer/ObjectModel/ISqlObjectVisitor.cs
index ed564f8..2ceb0b3 100644
--- a/src/Testing.Databases.SqlServer/ObjectModel/ISqlObjectVisitor.cs
+++ b/src/Testing.Databases.SqlServer/ObjectModel/ISqlObjectVisitor.cs
@@ -26,6 +26,13 @@ public interface ISqlObjectVisitor
/// The result of the visit.
TResult Visit(SqlColumn column);
+ ///
+ /// Visits the specified .
+ ///
+ /// to visit.
+ /// The result of the visit.
+ TResult Visit(SqlDefaultConstraint defaultConstraint);
+
///
/// Visits the specified .
///
diff --git a/src/Testing.Databases.SqlServer/ObjectModel/SqlColumn.cs b/src/Testing.Databases.SqlServer/ObjectModel/SqlColumn.cs
index 5577349..e30a345 100644
--- a/src/Testing.Databases.SqlServer/ObjectModel/SqlColumn.cs
+++ b/src/Testing.Databases.SqlServer/ObjectModel/SqlColumn.cs
@@ -82,6 +82,11 @@ internal SqlColumn(
///
public string? ComputedExpression { get; internal set; }
+ ///
+ /// Gets the default constraint of the column.
+ ///
+ public SqlDefaultConstraint? DefaultConstraint { get; internal set; }
+
///
public override TResult Accept(ISqlObjectVisitor visitor) => visitor.Visit(this);
diff --git a/src/Testing.Databases.SqlServer/ObjectModel/SqlDefaultConstraint.cs b/src/Testing.Databases.SqlServer/ObjectModel/SqlDefaultConstraint.cs
new file mode 100644
index 0000000..361d255
--- /dev/null
+++ b/src/Testing.Databases.SqlServer/ObjectModel/SqlDefaultConstraint.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Testing.Databases
+{
+ ///
+ /// Represents a default constraint of a .
+ ///
+ public class SqlDefaultConstraint : SqlObject
+ {
+ internal SqlDefaultConstraint(string name, string expression)
+ {
+ this.Name = name;
+ this.Expression = expression;
+ }
+
+ ///
+ /// Gets the name of the default constraint.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets the expression of the default constraint.
+ ///
+ public string Expression { get; }
+
+ ///
+ public override TResult Accept(ISqlObjectVisitor visitor) => visitor.Visit(this);
+
+ ///
+ public override string ToString()
+ {
+ return this.Name;
+ }
+ }
+}
diff --git a/src/Testing.Databases.SqlServer/SqlServer.cs b/src/Testing.Databases.SqlServer/SqlServer.cs
index 4351791..c848b12 100644
--- a/src/Testing.Databases.SqlServer/SqlServer.cs
+++ b/src/Testing.Databases.SqlServer/SqlServer.cs
@@ -51,6 +51,21 @@ public SqlServerDatabase CreateEmptyDatabase(string name)
return this.GetDatabase(name);
}
+ ///
+ /// Creates an empty database asynchronously in the SQL Server instance with the specified .
+ /// If the database already exists, it will be delete.
+ ///
+ /// Name of the database to create.
+ /// used to cancel the asynchronous operation.
+ /// A which represents the asynchronous operation and contains an instance of which allows to execute SQL commands/queries.
+ public async Task CreateEmptyDatabaseAsync(string name, CancellationToken cancellationToken = default)
+ {
+ await this.DeleteDatabaseAsync(name, cancellationToken);
+ await this.Master.ExecuteNonQueryAsync($"CREATE DATABASE [{name}]", cancellationToken);
+
+ return this.GetDatabase(name);
+ }
+
///
/// Deletes a database in the SQL server instance with the specified .
/// If the database does not exists, no exception is thrown.
@@ -62,6 +77,19 @@ public void DeleteDatabase(string name)
this.Master.ExecuteNonQuery($"IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = '{name}') DROP DATABASE [{name}]");
}
+ ///
+ /// Deletes a database asynchronously in the SQL server instance with the specified .
+ /// If the database does not exists, no exception is thrown.
+ ///
+ /// Name of the database to delete.
+ /// used to cancel the asynchronous operation.
+ /// A which represents the asynchronous operation.
+ public async Task DeleteDatabaseAsync(string name, CancellationToken cancellationToken = default)
+ {
+ await this.Master.ExecuteNonQueryAsync($"IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = '{name}') ALTER DATABASE [{name}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", cancellationToken);
+ await this.Master.ExecuteNonQueryAsync($"IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = '{name}') DROP DATABASE [{name}]", cancellationToken);
+ }
+
///
/// Gets an instance of the for the database specified with the .
///
diff --git a/src/Testing.Databases.SqlServer/SqlServerDatabaseExtensions.cs b/src/Testing.Databases.SqlServer/SqlServerDatabaseExtensions.cs
index 2026d2a..d70e371 100644
--- a/src/Testing.Databases.SqlServer/SqlServerDatabaseExtensions.cs
+++ b/src/Testing.Databases.SqlServer/SqlServerDatabaseExtensions.cs
@@ -54,6 +54,145 @@ public static int InsertInto(this SqlServerDatabase database, string tableNam
/// Set of object which represents the row to insert. Each object must have property which are mapped to the column to insert.
/// The number of the rows inserted.
public static int InsertInto(this SqlServerDatabase database, string tableName, bool disableIdentityInsert, params T[] objects)
+ {
+ var statement = BuildInsertStatement(tableName, disableIdentityInsert, objects);
+
+ return database.ExecuteNonQuery(statement);
+ }
+
+ ///
+ /// Insert data into the table asynchronously specified by the argument. The row
+ /// to insert are represents by objects (or anonymous objects) which the property name must match the
+ /// the column name.
+ ///
+ /// Type of the object which contains the data to insert in the table.
+ /// SQL Server database which contains the table where the data will be inserted.
+ /// SQL table where the data will be inserted.
+ /// Set of object which represents the row to insert. Each object must have property which are mapped to the column to insert.
+ /// A which represents the asynchronous operation and contains the number of the rows inserted.
+ public static async Task InsertIntoAsync(this SqlServerDatabase database, string tableName, params T[] objects)
+ {
+ return await InsertIntoAsync(database, tableName, false, objects);
+ }
+
+ ///
+ /// Insert data into the table asynchronously specified by the argument. The row
+ /// to insert are represents by objects (or anonymous objects) which the property name must match the
+ /// the column name.
+ ///
+ /// Type of the object which contains the data to insert in the table.
+ /// SQL Server database which contains the table where the data will be inserted.
+ /// SQL table where the data will be inserted.
+ /// to disable auto incrementation of the IDENTITY column. In this case, the object must contains explicitely the value of the IDENTITY
+ /// column to insert.
+ /// Set of object which represents the row to insert. Each object must have property which are mapped to the column to insert.
+ /// A which represents the asynchronous operation and contains the number of the rows inserted.
+ public static Task InsertIntoAsync(this SqlServerDatabase database, string tableName, bool disableIdentityInsert, params T[] objects)
+ {
+ var statement = BuildInsertStatement(tableName, disableIdentityInsert, objects);
+
+ return database.ExecuteNonQueryAsync(statement);
+ }
+
+ ///
+ /// Clear all in the database.
+ ///
+ /// SQL Server database which the data have to be deleted.
+ public static void ClearAllData(this SqlServerDatabase database)
+ {
+ foreach (var statement in GetClearDataStatements())
+ {
+ database.ExecuteNonQuery(statement);
+ }
+ }
+
+ ///
+ /// Clear all in the database asynchronously.
+ ///
+ /// SQL Server database which the data have to be deleted.
+ /// used to cancel the asynchronous operation.
+ /// A which represents the asynchronous operation.
+ public static async Task ClearAllDataAsync(this SqlServerDatabase database, CancellationToken cancellationToken = default)
+ {
+ foreach (var statement in GetClearDataStatements())
+ {
+ await database.ExecuteNonQueryAsync(statement, cancellationToken);
+ }
+ }
+
+ ///
+ /// Execute an T-SQL script on the .
+ ///
+ /// where the will be executed.
+ /// T-SQL script to execute.
+ public static void ExecuteScript(this SqlServerDatabase database, string script)
+ {
+ using var stringReader = new StringReader(script);
+
+ ExecuteScript(database, stringReader);
+ }
+
+ ///
+ /// Execute an T-SQL script on the .
+ ///
+ /// where the will be executed.
+ /// which contains the T-SQL script to execute.
+ public static void ExecuteScript(this SqlServerDatabase database, StringReader script)
+ {
+ var parser = new SqlServerScriptParser(script);
+
+ var block = parser.ReadNextBlock();
+
+ while (block is not null)
+ {
+ for (var i = 0; i < block.Count; i++)
+ {
+ database.ExecuteNonQuery(block.Code);
+ }
+
+ block = parser.ReadNextBlock();
+ }
+ }
+
+ ///
+ /// Execute an T-SQL script on the .
+ ///
+ /// where the will be executed.
+ /// T-SQL script to execute.
+ /// used to cancel the asynchronous operation.
+ /// A which represents the asynchronous operation.
+ public static async Task ExecuteScriptAsync(this SqlServerDatabase database, string script, CancellationToken cancellationToken = default)
+ {
+ using var stringReader = new StringReader(script);
+
+ await ExecuteScriptAsync(database, stringReader);
+ }
+
+ ///
+ /// Execute an T-SQL script on the asynchronously.
+ ///
+ /// where the will be executed.
+ /// which contains the T-SQL script to execute.
+ /// used to cancel the asynchronous operation.
+ /// A which represents the asynchronous operation.
+ public static async Task ExecuteScriptAsync(this SqlServerDatabase database, StringReader script, CancellationToken cancellationToken = default)
+ {
+ var parser = new SqlServerScriptParser(script);
+
+ var block = parser.ReadNextBlock();
+
+ while (block is not null)
+ {
+ for (var i = 0; i < block.Count; i++)
+ {
+ await database.ExecuteNonQueryAsync(block.Code, cancellationToken);
+ }
+
+ block = parser.ReadNextBlock();
+ }
+ }
+
+ private static string BuildInsertStatement(string tableName, bool disableIdentityInsert, params T[] objects)
{
var builder = new SqlInsertStatementBuilder(tableName);
var properties = typeof(T).GetProperties();
@@ -91,24 +230,16 @@ Type t when Array.Exists(AuthorizedNonStringTypes, at => at == t) => builder.Add
statement = $"SET IDENTITY_INSERT [{tableName}] ON;" + statement + $"SET IDENTITY_INSERT [{tableName}] OFF;";
}
- return database.ExecuteNonQuery(statement);
+ return statement;
}
- ///
- /// Clear all in the database.
- ///
- /// SQL Server database which the data have to be deleted.
- public static void ClearAllData(this SqlServerDatabase database)
+ private static string[] GetClearDataStatements()
{
- database.ExecuteNonQuery("EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
-
- database.ExecuteNonQuery("EXEC sp_msforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'");
-
- // Re-initialize the seed of the IDENTITY columns.
- // For each table which contains an IDENTITY column, execute the following SQL statement:
- // DBCC CHECKIDENT ('[].[]', RESEED, )
- database.ExecuteNonQuery(@"
- DECLARE @sqlcmd VARCHAR(MAX);
+ return
+ [
+ "EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'",
+ "EXEC sp_msforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'",
+ @"DECLARE @sqlcmd VARCHAR(MAX);
SET @sqlcmd = (
SELECT STRING_AGG(CAST('DBCC CHECKIDENT (''[' + [s].[name] + '].[' + [t].[name] + ']'', RESEED, ' + CAST([ic].[seed_value] AS VARCHAR(20)) + ')' AS NVARCHAR(MAX)),';' + CHAR(10)) WITHIN GROUP (ORDER BY [t].[name])
@@ -125,43 +256,9 @@ [sys].[identity_columns] AS [ic]
AND [c].[column_id] = [ic].[column_id]
)
- EXEC (@sqlcmd)");
-
- database.ExecuteNonQuery("EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'");
- }
-
- ///
- /// Execute an T-SQL script on the .
- ///
- /// where the will be executed.
- /// T-SQL script to execute.
- public static void ExecuteScript(this SqlServerDatabase database, string script)
- {
- using var stringReader = new StringReader(script);
-
- ExecuteScript(database, stringReader);
- }
-
- ///
- /// Execute an T-SQL script on the .
- ///
- /// where the will be executed.
- /// which contains the T-SQL script to execute.
- public static void ExecuteScript(this SqlServerDatabase database, StringReader script)
- {
- var parser = new SqlServerScriptParser(script);
-
- var block = parser.ReadNextBlock();
-
- while (block is not null)
- {
- for (var i = 0; i < block.Count; i++)
- {
- database.ExecuteNonQuery(block.Code);
- }
-
- block = parser.ReadNextBlock();
- }
+ EXEC (@sqlcmd)",
+ "EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'",
+ ];
}
private sealed class SqlInsertStatementBuilder
diff --git a/src/Testing.Databases.SqlServer/SqlServerDatabaseObjectExtensions.cs b/src/Testing.Databases.SqlServer/SqlServerDatabaseObjectExtensions.cs
index 68d234e..746e134 100644
--- a/src/Testing.Databases.SqlServer/SqlServerDatabaseObjectExtensions.cs
+++ b/src/Testing.Databases.SqlServer/SqlServerDatabaseObjectExtensions.cs
@@ -75,6 +75,9 @@ ORDER BY
// Gets the check constraints
var allCheckConstraints = GetCheckConstraintsAsync(database, cancellationToken);
+ // Gets the default constraints
+ var allDefaultConstraints = GetDefaultConstraintsAsync(database, cancellationToken);
+
// Gets the indexes
var allForeignKeys = GetForeignKeysAsync(database, cancellationToken);
@@ -90,7 +93,7 @@ ORDER BY
// Gets the unique constraints
var allUniqueConstraints = GetUniqueConstraintsAsync(database, cancellationToken);
- await Task.WhenAll(allColumns, allCheckConstraints, allForeignKeys, allIndexes, allPrimaryKeys, allTriggers, allUniqueConstraints);
+ await Task.WhenAll(allColumns, allCheckConstraints, allDefaultConstraints, allForeignKeys, allIndexes, allPrimaryKeys, allTriggers, allUniqueConstraints);
// Builds the SqlTable object
foreach (var table in result.Rows.Cast())
@@ -108,12 +111,17 @@ ORDER BY
var columnsTable = allColumns.Result[(int)table["Id"]];
var columns = new List();
+ var defaultConstraintsTable = allDefaultConstraints.Result[(int)table["Id"]];
+
foreach (var column in columnsTable.OrderBy(r => r["Position"]))
{
- columns.Add(ToColumn(column));
+ var position = Convert.ToInt32(column["Position"], CultureInfo.InvariantCulture);
+ var defaultConstraint = defaultConstraintsTable.SingleOrDefault(r => (int)r["ColumnId"] == position);
+
+ columns.Add(ToColumn(column, defaultConstraint));
}
- // Indexes
+ // Foreign keys
var foreignKeysTable = allForeignKeys.Result[(int)table["Id"]];
var foreignKeys = new List();
@@ -308,6 +316,28 @@ [sys].[types] AS [ty]
return result.Rows.Cast().ToLookup(c => (int)c["TableId"]);
}
+ private static async Task> GetDefaultConstraintsAsync(SqlServerDatabase database, CancellationToken cancellationToken)
+ {
+ const string sql = @"
+ SELECT
+ [t].[object_id] AS [TableId],
+ [df].[parent_column_id] AS [ColumnId],
+ [df].[name] AS [Name],
+ [df].[definition] AS [Expression]
+ FROM
+ [sys].[default_constraints] AS [df],
+ [sys].[tables] AS [t]
+ WHERE
+ [df].[parent_object_id] = [t].[object_id]
+ ORDER BY
+ [t].[name],
+ [df].[name]";
+
+ var result = await database.ExecuteQueryAsync(sql, cancellationToken);
+
+ return result.Rows.Cast().ToLookup(row => (int)row["TableId"]);
+ }
+
private static async Task> GetForeignKeysAsync(SqlServerDatabase database, CancellationToken cancellationToken)
{
const string sql = @"
@@ -468,7 +498,7 @@ private static SqlCheckConstraint ToCheckConstraint(DataRow row)
return new SqlCheckConstraint((string)row["Name"], (string)row["Code"]);
}
- private static SqlColumn ToColumn(DataRow row)
+ private static SqlColumn ToColumn(DataRow row, DataRow? defaultConstraintRow)
{
return new SqlColumn(
(string)row["Name"],
@@ -480,12 +510,20 @@ private static SqlColumn ToColumn(DataRow row)
{
CollationName = NullIfDbNull(row["CollationName"]),
ComputedExpression = NullIfDbNull(row["ComputedExpression"]),
+ DefaultConstraint = defaultConstraintRow != null ? ToDefaultConstraint(defaultConstraintRow) : null,
IsComputed = (bool)row["IsComputed"],
IsIdentity = (bool)row["IsIdentity"],
IsNullable = (bool)row["IsNullable"],
};
}
+ private static SqlDefaultConstraint ToDefaultConstraint(DataRow row)
+ {
+ return new SqlDefaultConstraint(
+ (string)row["Name"],
+ (string)row["Expression"]);
+ }
+
private static SqlForeignKey ToForeignKey(DataRow row, IList columns)
{
return new SqlForeignKey((string)row["ForeignKeyName"], (string)row["ReferencedTableName"], (string)row["UpdateAction"], (string)row["DeleteAction"], columns);
diff --git a/tests/Testing.Databases.SqlServer.EntityFramework.Tests/EntityFrameworkSqlServerExtensionsTest.cs b/tests/Testing.Databases.SqlServer.EntityFramework.Tests/EntityFrameworkSqlServerExtensionsTest.cs
index 232eb0b..1321b05 100644
--- a/tests/Testing.Databases.SqlServer.EntityFramework.Tests/EntityFrameworkSqlServerExtensionsTest.cs
+++ b/tests/Testing.Databases.SqlServer.EntityFramework.Tests/EntityFrameworkSqlServerExtensionsTest.cs
@@ -24,7 +24,7 @@ public async Task Create_WithNoExistingDatabase()
var server = new SqlServer(ConnectionString);
server.DeleteDatabase(nameof(EntityFrameworkSqlServerExtensionsTest));
- var database = await server.CreateDatabaseAsync(nameof(EntityFrameworkSqlServerExtensionsTest), dbContext);
+ var database = server.CreateDatabase(nameof(EntityFrameworkSqlServerExtensionsTest), dbContext);
database.ConnectionString.Should().Be("Data Source=(localDB)\\posinfo-tests;Initial Catalog=EntityFrameworkSqlServerExtensionsTest;Integrated Security=True");
@@ -52,6 +52,60 @@ public async Task Create_WithAlreadyExistingDatabase()
emptyDatabase.ExecuteNonQuery("CREATE TABLE [MustBeDeleted] ([Id] INT)");
+ var database = server.CreateDatabase(nameof(EntityFrameworkSqlServerExtensionsTest), dbContext);
+
+ database.ConnectionString.Should().Be("Data Source=(localDB)\\posinfo-tests;Initial Catalog=EntityFrameworkSqlServerExtensionsTest;Integrated Security=True");
+
+ var tables = await database.GetTablesAsync();
+
+ tables.Should().HaveCount(1);
+
+ tables[0].Name.Should().Be("Entity");
+
+ tables[0].Columns.Should().HaveCount(2);
+ tables[0].Columns[0].Name.Should().Be("Id");
+ tables[0].Columns[1].Name.Should().Be("Name");
+ }
+
+ [Fact]
+ public async Task CreateAsync_WithNoExistingDatabase()
+ {
+ var optionsBuilder = new DbContextOptionsBuilder()
+ .UseSqlServer("Data Source=OtherServer;");
+
+ using var dbContext = new DbContextTest(optionsBuilder.Options);
+
+ var server = new SqlServer(ConnectionString);
+ await server.DeleteDatabaseAsync(nameof(EntityFrameworkSqlServerExtensionsTest));
+
+ var database = await server.CreateDatabaseAsync(nameof(EntityFrameworkSqlServerExtensionsTest), dbContext);
+
+ database.ConnectionString.Should().Be("Data Source=(localDB)\\posinfo-tests;Initial Catalog=EntityFrameworkSqlServerExtensionsTest;Integrated Security=True");
+
+ var tables = await database.GetTablesAsync();
+
+ tables.Should().HaveCount(1);
+
+ tables[0].Name.Should().Be("Entity");
+
+ tables[0].Columns.Should().HaveCount(2);
+ tables[0].Columns[0].Name.Should().Be("Id");
+ tables[0].Columns[1].Name.Should().Be("Name");
+ }
+
+ [Fact]
+ public async Task CreateAsync_WithAlreadyExistingDatabase()
+ {
+ var optionsBuilder = new DbContextOptionsBuilder()
+ .UseSqlServer("Data Source=OtherServer;");
+
+ using var dbContext = new DbContextTest(optionsBuilder.Options);
+
+ var server = new SqlServer(ConnectionString);
+ var emptyDatabase = await server.CreateEmptyDatabaseAsync(nameof(EntityFrameworkSqlServerExtensionsTest));
+
+ await emptyDatabase.ExecuteNonQueryAsync("CREATE TABLE [MustBeDeleted] ([Id] INT)");
+
var database = await server.CreateDatabaseAsync(nameof(EntityFrameworkSqlServerExtensionsTest), dbContext);
database.ConnectionString.Should().Be("Data Source=(localDB)\\posinfo-tests;Initial Catalog=EntityFrameworkSqlServerExtensionsTest;Integrated Security=True");
diff --git a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableDifference.sql b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableDifference.sql
index 7c38350..0c44ec2 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableDifference.sql
+++ b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableDifference.sql
@@ -10,4 +10,7 @@
[Computed] AS [Scale] + [Precision],
[SourceColumn] INT NOT NULL,
[IdenticalColumn] INT NOT NULL,
+ [ColumnWithDefaultConstraint] VARCHAR(20) NOT NULL CONSTRAINT DF_TableDifference_ColumnWithDefaultConstraint DEFAULT 'Source expression',
+ [ColumnWithMissingDefaultConstraint] VARCHAR(20) NOT NULL CONSTRAINT DF_TableDifference_ColumnWithMissingDefaultConstraint DEFAULT 'Default value',
+ [ColumnWithOtherDefaultConstraintName] VARCHAR(20) NOT NULL CONSTRAINT DF_TableDifference_ColumnWithOtherDefaultConstraintName DEFAULT 'Same expression',
)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableIdentical.sql b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableIdentical.sql
index fed9652..95b8acc 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableIdentical.sql
+++ b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableIdentical.sql
@@ -1,6 +1,6 @@
CREATE TABLE [dbo].[TableIdentical]
(
[Id] INT NOT NULL,
- [ForeignKeyId] INT NOT NULL,
+ [ForeignKeyId] INT NOT NULL CONSTRAINT DF_TableIdentical_ForeignKeyId DEFAULT (1 + 2 + 3),
[IncludeColumn] INT NOT NULL,
)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableSource.sql b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableSource.sql
index 8ac53e6..5c40f93 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableSource.sql
+++ b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableSource.sql
@@ -1,6 +1,6 @@
CREATE TABLE [dbo].[TableSource]
(
[Id] INT NOT NULL,
- [SourceName] VARCHAR(50),
+ [SourceName] VARCHAR(50) CONSTRAINT DF_TableSource_SourceName DEFAULT 'Source',
[SourceForeignKeyId] INT NOT NULL,
)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableWithDifferentPrimaryKey.sql b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableWithDifferentPrimaryKey.sql
new file mode 100644
index 0000000..1dbe63a
--- /dev/null
+++ b/tests/Testing.Databases.SqlServer.Tests.Source/Tables/TableWithDifferentPrimaryKey.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [dbo].[TableWithDifferentPrimaryKey]
+(
+ [Id] INT NOT NULL,
+
+ CONSTRAINT [PK_TableWithDifferentPrimaryKey_Source] PRIMARY KEY CLUSTERED ([Id] ASC)
+)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Source/Testing.Databases.SqlServer.Tests.Source.sqlproj b/tests/Testing.Databases.SqlServer.Tests.Source/Testing.Databases.SqlServer.Tests.Source.sqlproj
index 05104a8..b17888a 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Source/Testing.Databases.SqlServer.Tests.Source.sqlproj
+++ b/tests/Testing.Databases.SqlServer.Tests.Source/Testing.Databases.SqlServer.Tests.Source.sqlproj
@@ -101,5 +101,6 @@
+
\ No newline at end of file
diff --git a/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableDifference.sql b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableDifference.sql
index 5eebfed..fafa34e 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableDifference.sql
+++ b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableDifference.sql
@@ -10,4 +10,7 @@
[Computed] AS [Scale] - [Precision],
[TargetColumn] INT NOT NULL,
[IdenticalColumn] INT NOT NULL,
+ [ColumnWithDefaultConstraint] VARCHAR(20) NOT NULL CONSTRAINT DF_TableDifference_ColumnWithDefaultConstraint DEFAULT 'Target expression',
+ [ColumnWithMissingDefaultConstraint] VARCHAR(20) NOT NULL,
+ [ColumnWithOtherDefaultConstraintName] VARCHAR(20) NOT NULL CONSTRAINT DF_TableDifference_WrongName DEFAULT 'Same expression',
)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableTarget.sql b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableTarget.sql
index 18ce924..93f9aa3 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableTarget.sql
+++ b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableTarget.sql
@@ -1,6 +1,6 @@
CREATE TABLE [dbo].[TableTarget]
(
[Id] INT NOT NULL,
- [TargetName] VARCHAR(50),
+ [TargetName] VARCHAR(50) CONSTRAINT DF_TableTarget_TargetName DEFAULT 'Target',
[TargetForeignKeyId] INT NOT NULL,
)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableWithDifferentPrimaryKey.sql b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableWithDifferentPrimaryKey.sql
new file mode 100644
index 0000000..fdc64c8
--- /dev/null
+++ b/tests/Testing.Databases.SqlServer.Tests.Target/Tables/TableWithDifferentPrimaryKey.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [dbo].[TableWithDifferentPrimaryKey]
+(
+ [Id] INT NOT NULL,
+
+ CONSTRAINT [PK_TableWithDifferentPrimaryKey_Target] PRIMARY KEY CLUSTERED ([Id] ASC)
+)
diff --git a/tests/Testing.Databases.SqlServer.Tests.Target/Testing.Databases.SqlServer.Tests.Target.sqlproj b/tests/Testing.Databases.SqlServer.Tests.Target/Testing.Databases.SqlServer.Tests.Target.sqlproj
index 8728546..6c3b10a 100644
--- a/tests/Testing.Databases.SqlServer.Tests.Target/Testing.Databases.SqlServer.Tests.Target.sqlproj
+++ b/tests/Testing.Databases.SqlServer.Tests.Target/Testing.Databases.SqlServer.Tests.Target.sqlproj
@@ -115,5 +115,6 @@
+
\ No newline at end of file
diff --git a/tests/Testing.Databases.SqlServer.Tests/ObjectModel/SqlDefaultConstraintTest.cs b/tests/Testing.Databases.SqlServer.Tests/ObjectModel/SqlDefaultConstraintTest.cs
new file mode 100644
index 0000000..a15bd43
--- /dev/null
+++ b/tests/Testing.Databases.SqlServer.Tests/ObjectModel/SqlDefaultConstraintTest.cs
@@ -0,0 +1,19 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Testing.Databases.Tests
+{
+ public class SqlDefaultConstraintTest
+ {
+ [Fact]
+ public void ToStringTest()
+ {
+ var defaultConstraint = new SqlDefaultConstraint("The name", default);
+
+ defaultConstraint.ToString().Should().Be("The name");
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.CompareAsync.txt b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.CompareAsync.txt
index b7f510d..f4378c9 100644
--- a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.CompareAsync.txt
+++ b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.CompareAsync.txt
@@ -53,6 +53,21 @@
Source: ([Scale]+[Precision])
Target: ([Scale]-[Precision])
- TargetColumn (Missing in the source)
+ - ColumnWithDefaultConstraint
+ ------ Default constraint ------
+ - DF_TableDifference_ColumnWithDefaultConstraint
+ * Expression:
+ Source: ('Source expression')
+ Target: ('Target expression')
+ - ColumnWithMissingDefaultConstraint
+ ------ Default constraint ------
+ - DF_TableDifference_ColumnWithMissingDefaultConstraint (Missing in the target)
+ - ColumnWithOtherDefaultConstraintName
+ ------ Default constraint ------
+ - DF_TableDifference_ColumnWithOtherDefaultConstraintName
+ * Name:
+ Source: DF_TableDifference_ColumnWithOtherDefaultConstraintName
+ Target: DF_TableDifference_WrongName
- SourceColumn (Missing in the target)
------ Foreign keys ------
- ForeignKeyDifference
@@ -99,7 +114,8 @@
* Position:
Source: 1
Target: 2
- ------ Primary key ------
+ ------ Primary key ------
+ - PrimaryKeyDifference
* Type:
Source: NONCLUSTERED
Target: CLUSTERED
@@ -149,6 +165,15 @@
Source: 1
Target: 2
- dbo.TableTarget (Missing in the source)
+- dbo.TableWithDifferentPrimaryKey
+ ------ Indexes ------
+ - PK_TableWithDifferentPrimaryKey_Target (Missing in the source)
+ - PK_TableWithDifferentPrimaryKey_Source (Missing in the target)
+ ------ Primary key ------
+ - PK_TableWithDifferentPrimaryKey_Source
+ * Name:
+ Source: PK_TableWithDifferentPrimaryKey_Source
+ Target: PK_TableWithDifferentPrimaryKey_Target
- dbo.TableSource (Missing in the target)
------ Stored procedures ------
- dbo.StoredProcedureDifference
diff --git a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.cs b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.cs
index 79b6593..4924451 100644
--- a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.cs
+++ b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseComparerTest.cs
@@ -52,7 +52,7 @@ public async Task CompareAsync()
differences.StoredProcedures[2].Target.Should().BeNull();
// Tables
- differences.Tables.Should().HaveCount(3);
+ differences.Tables.Should().HaveCount(4);
differences.Tables[0].Source.Name.Should().Be("TableDifference");
differences.Tables[0].Source.Schema.Should().Be("dbo");
@@ -78,10 +78,11 @@ public async Task CompareAsync()
differences.Tables[0].CheckConstraints[0].Type.Should().Be(SqlObjectDifferenceType.Different);
// Tables / Columns
- differences.Tables[0].Source.Columns.Should().HaveCount(10);
+ differences.Tables[0].Source.Columns.Should().HaveCount(13);
differences.Tables[0].Source.Columns[0].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[0].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[0].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[0].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[0].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[0].IsNullable.Should().BeFalse();
@@ -94,6 +95,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[1].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
differences.Tables[0].Source.Columns[1].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[1].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[1].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[1].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[1].IsNullable.Should().BeTrue();
@@ -106,6 +108,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[2].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
differences.Tables[0].Source.Columns[2].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[2].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[2].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[2].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[2].IsNullable.Should().BeFalse();
@@ -118,6 +121,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[3].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[3].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[3].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[3].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[3].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[3].IsNullable.Should().BeFalse();
@@ -130,6 +134,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[4].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[4].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[4].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[4].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[4].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[4].IsNullable.Should().BeFalse();
@@ -142,6 +147,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[5].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[5].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[5].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[5].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[5].IsIdentity.Should().BeTrue();
differences.Tables[0].Source.Columns[5].IsNullable.Should().BeFalse();
@@ -154,6 +160,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[6].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[6].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[6].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[6].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[6].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[6].IsNullable.Should().BeTrue();
@@ -166,6 +173,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[7].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[7].ComputedExpression.Should().Be("([Scale]+[Precision])");
+ differences.Tables[0].Source.Columns[7].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[7].IsComputed.Should().BeTrue();
differences.Tables[0].Source.Columns[7].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[7].IsNullable.Should().BeTrue();
@@ -178,6 +186,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[8].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[8].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[8].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[8].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[8].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[8].IsNullable.Should().BeFalse();
@@ -190,6 +199,7 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[9].CollationName.Should().BeNull();
differences.Tables[0].Source.Columns[9].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[9].DefaultConstraint.Should().BeNull();
differences.Tables[0].Source.Columns[9].IsComputed.Should().BeFalse();
differences.Tables[0].Source.Columns[9].IsIdentity.Should().BeFalse();
differences.Tables[0].Source.Columns[9].IsNullable.Should().BeFalse();
@@ -200,13 +210,56 @@ public async Task CompareAsync()
differences.Tables[0].Source.Columns[9].Scale.Should().Be(0);
differences.Tables[0].Source.Columns[9].TypeName.Should().Be("int");
+ differences.Tables[0].Source.Columns[10].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Source.Columns[10].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[10].DefaultConstraint.Expression.Should().Be("('Source expression')");
+ differences.Tables[0].Source.Columns[10].DefaultConstraint.Name.Should().Be("DF_TableDifference_ColumnWithDefaultConstraint");
+ differences.Tables[0].Source.Columns[10].IsComputed.Should().BeFalse();
+ differences.Tables[0].Source.Columns[10].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Source.Columns[10].IsNullable.Should().BeFalse();
+ differences.Tables[0].Source.Columns[10].MaxLength.Should().Be(20);
+ differences.Tables[0].Source.Columns[10].Name.Should().Be("ColumnWithDefaultConstraint");
+ differences.Tables[0].Source.Columns[10].Position.Should().Be(11);
+ differences.Tables[0].Source.Columns[10].Precision.Should().Be(0);
+ differences.Tables[0].Source.Columns[10].Scale.Should().Be(0);
+ differences.Tables[0].Source.Columns[10].TypeName.Should().Be("varchar");
+
+ differences.Tables[0].Source.Columns[11].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Source.Columns[11].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[11].DefaultConstraint.Expression.Should().Be("('Default value')");
+ differences.Tables[0].Source.Columns[11].DefaultConstraint.Name.Should().Be("DF_TableDifference_ColumnWithMissingDefaultConstraint");
+ differences.Tables[0].Source.Columns[11].IsComputed.Should().BeFalse();
+ differences.Tables[0].Source.Columns[11].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Source.Columns[11].IsNullable.Should().BeFalse();
+ differences.Tables[0].Source.Columns[11].MaxLength.Should().Be(20);
+ differences.Tables[0].Source.Columns[11].Name.Should().Be("ColumnWithMissingDefaultConstraint");
+ differences.Tables[0].Source.Columns[11].Position.Should().Be(12);
+ differences.Tables[0].Source.Columns[11].Precision.Should().Be(0);
+ differences.Tables[0].Source.Columns[11].Scale.Should().Be(0);
+ differences.Tables[0].Source.Columns[11].TypeName.Should().Be("varchar");
+
+ differences.Tables[0].Source.Columns[12].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Source.Columns[12].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Source.Columns[12].DefaultConstraint.Expression.Should().Be("('Same expression')");
+ differences.Tables[0].Source.Columns[12].DefaultConstraint.Name.Should().Be("DF_TableDifference_ColumnWithOtherDefaultConstraintName");
+ differences.Tables[0].Source.Columns[12].IsComputed.Should().BeFalse();
+ differences.Tables[0].Source.Columns[12].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Source.Columns[12].IsNullable.Should().BeFalse();
+ differences.Tables[0].Source.Columns[12].MaxLength.Should().Be(20);
+ differences.Tables[0].Source.Columns[12].Name.Should().Be("ColumnWithOtherDefaultConstraintName");
+ differences.Tables[0].Source.Columns[12].Position.Should().Be(13);
+ differences.Tables[0].Source.Columns[12].Precision.Should().Be(0);
+ differences.Tables[0].Source.Columns[12].Scale.Should().Be(0);
+ differences.Tables[0].Source.Columns[12].TypeName.Should().Be("varchar");
+
differences.Tables[0].Target.Name.Should().Be("TableDifference");
differences.Tables[0].Target.Schema.Should().Be("dbo");
- differences.Tables[0].Target.Columns.Should().HaveCount(10);
+ differences.Tables[0].Target.Columns.Should().HaveCount(13);
differences.Tables[0].Target.Columns[0].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
differences.Tables[0].Target.Columns[0].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[0].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[0].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[0].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[0].IsNullable.Should().BeFalse();
@@ -219,6 +272,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[1].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
differences.Tables[0].Target.Columns[1].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[1].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[1].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[1].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[1].IsNullable.Should().BeFalse();
@@ -231,6 +285,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[2].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[2].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[2].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[2].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[2].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[2].IsNullable.Should().BeFalse();
@@ -243,6 +298,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[3].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
differences.Tables[0].Target.Columns[3].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[3].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[3].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[3].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[3].IsNullable.Should().BeFalse();
@@ -255,6 +311,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[4].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[4].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[4].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[4].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[4].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[4].IsNullable.Should().BeFalse();
@@ -267,6 +324,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[5].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[5].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[5].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[5].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[5].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[5].IsNullable.Should().BeFalse();
@@ -279,6 +337,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[6].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[6].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[6].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[6].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[6].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[6].IsNullable.Should().BeTrue();
@@ -291,6 +350,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[7].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[7].ComputedExpression.Should().Be("([Scale]-[Precision])");
+ differences.Tables[0].Target.Columns[7].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[7].IsComputed.Should().BeTrue();
differences.Tables[0].Target.Columns[7].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[7].IsNullable.Should().BeTrue();
@@ -303,6 +363,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[8].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[8].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[8].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[8].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[8].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[8].IsNullable.Should().BeFalse();
@@ -315,6 +376,7 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[9].CollationName.Should().BeNull();
differences.Tables[0].Target.Columns[9].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[9].DefaultConstraint.Should().BeNull();
differences.Tables[0].Target.Columns[9].IsComputed.Should().BeFalse();
differences.Tables[0].Target.Columns[9].IsIdentity.Should().BeFalse();
differences.Tables[0].Target.Columns[9].IsNullable.Should().BeFalse();
@@ -325,43 +387,123 @@ public async Task CompareAsync()
differences.Tables[0].Target.Columns[9].Scale.Should().Be(0);
differences.Tables[0].Target.Columns[9].TypeName.Should().Be("int");
- differences.Tables[0].Columns.Should().HaveCount(9);
-
+ differences.Tables[0].Target.Columns[10].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Target.Columns[10].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[10].DefaultConstraint.Expression.Should().Be("('Target expression')");
+ differences.Tables[0].Target.Columns[10].DefaultConstraint.Name.Should().Be("DF_TableDifference_ColumnWithDefaultConstraint");
+ differences.Tables[0].Target.Columns[10].IsComputed.Should().BeFalse();
+ differences.Tables[0].Target.Columns[10].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Target.Columns[10].IsNullable.Should().BeFalse();
+ differences.Tables[0].Target.Columns[10].MaxLength.Should().Be(20);
+ differences.Tables[0].Target.Columns[10].Name.Should().Be("ColumnWithDefaultConstraint");
+ differences.Tables[0].Target.Columns[10].Position.Should().Be(11);
+ differences.Tables[0].Target.Columns[10].Precision.Should().Be(0);
+ differences.Tables[0].Target.Columns[10].Scale.Should().Be(0);
+ differences.Tables[0].Target.Columns[10].TypeName.Should().Be("varchar");
+
+ differences.Tables[0].Target.Columns[11].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Target.Columns[11].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[11].DefaultConstraint.Should().BeNull();
+ differences.Tables[0].Target.Columns[11].IsComputed.Should().BeFalse();
+ differences.Tables[0].Target.Columns[11].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Target.Columns[11].IsNullable.Should().BeFalse();
+ differences.Tables[0].Target.Columns[11].MaxLength.Should().Be(20);
+ differences.Tables[0].Target.Columns[11].Name.Should().Be("ColumnWithMissingDefaultConstraint");
+ differences.Tables[0].Target.Columns[11].Position.Should().Be(12);
+ differences.Tables[0].Target.Columns[11].Precision.Should().Be(0);
+ differences.Tables[0].Target.Columns[11].Scale.Should().Be(0);
+ differences.Tables[0].Target.Columns[11].TypeName.Should().Be("varchar");
+
+ differences.Tables[0].Target.Columns[12].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[0].Target.Columns[12].ComputedExpression.Should().BeNull();
+ differences.Tables[0].Target.Columns[12].DefaultConstraint.Expression.Should().Be("('Same expression')");
+ differences.Tables[0].Target.Columns[12].DefaultConstraint.Name.Should().Be("DF_TableDifference_WrongName");
+ differences.Tables[0].Target.Columns[12].IsComputed.Should().BeFalse();
+ differences.Tables[0].Target.Columns[12].IsIdentity.Should().BeFalse();
+ differences.Tables[0].Target.Columns[12].IsNullable.Should().BeFalse();
+ differences.Tables[0].Target.Columns[12].MaxLength.Should().Be(20);
+ differences.Tables[0].Target.Columns[12].Name.Should().Be("ColumnWithOtherDefaultConstraintName");
+ differences.Tables[0].Target.Columns[12].Position.Should().Be(13);
+ differences.Tables[0].Target.Columns[12].Precision.Should().Be(0);
+ differences.Tables[0].Target.Columns[12].Scale.Should().Be(0);
+ differences.Tables[0].Target.Columns[12].TypeName.Should().Be("varchar");
+
+ differences.Tables[0].Columns.Should().HaveCount(12);
+
+ differences.Tables[0].Columns[0].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[0].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[0]);
differences.Tables[0].Columns[0].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[0]);
differences.Tables[0].Columns[0].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[1].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[1].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[1]);
differences.Tables[0].Columns[1].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[1]);
differences.Tables[0].Columns[1].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[2].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[2].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[3]);
differences.Tables[0].Columns[2].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[2]);
differences.Tables[0].Columns[2].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[3].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[3].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[2]);
differences.Tables[0].Columns[3].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[3]);
differences.Tables[0].Columns[3].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[4].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[4].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[4]);
differences.Tables[0].Columns[4].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[4]);
differences.Tables[0].Columns[4].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[5].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[5].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[5]);
differences.Tables[0].Columns[5].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[5]);
differences.Tables[0].Columns[5].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[6].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[6].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[7]);
differences.Tables[0].Columns[6].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[7]);
differences.Tables[0].Columns[6].Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[7].DefaultConstraint.Should().BeNull();
differences.Tables[0].Columns[7].Source.Should().BeNull();
differences.Tables[0].Columns[7].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[8]);
differences.Tables[0].Columns[7].Type.Should().Be(SqlObjectDifferenceType.MissingInSource);
- differences.Tables[0].Columns[8].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[8]);
- differences.Tables[0].Columns[8].Target.Should().BeNull();
- differences.Tables[0].Columns[8].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
+ differences.Tables[0].Columns[8].DefaultConstraint.Source.Should().BeSameAs(differences.Tables[0].Source.Columns[10].DefaultConstraint);
+ differences.Tables[0].Columns[8].DefaultConstraint.Target.Should().BeSameAs(differences.Tables[0].Target.Columns[10].DefaultConstraint);
+ differences.Tables[0].Columns[8].DefaultConstraint.Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[8].DefaultConstraint.Properties.Should().HaveCount(1);
+ differences.Tables[0].Columns[8].DefaultConstraint.Properties[0].Name.Should().Be("Expression");
+ differences.Tables[0].Columns[8].DefaultConstraint.Properties[0].Source.Should().Be("('Source expression')");
+ differences.Tables[0].Columns[8].DefaultConstraint.Properties[0].Target.Should().Be("('Target expression')");
+ differences.Tables[0].Columns[8].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[10]);
+ differences.Tables[0].Columns[8].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[10]);
+ differences.Tables[0].Columns[8].Type.Should().Be(SqlObjectDifferenceType.Different);
+
+ differences.Tables[0].Columns[9].DefaultConstraint.Source.Should().BeSameAs(differences.Tables[0].Source.Columns[11].DefaultConstraint);
+ differences.Tables[0].Columns[9].DefaultConstraint.Target.Should().BeSameAs(differences.Tables[0].Target.Columns[11].DefaultConstraint);
+ differences.Tables[0].Columns[9].DefaultConstraint.Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
+ differences.Tables[0].Columns[9].DefaultConstraint.Properties.Should().BeEmpty();
+ differences.Tables[0].Columns[9].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[11]);
+ differences.Tables[0].Columns[9].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[11]);
+ differences.Tables[0].Columns[9].Type.Should().Be(SqlObjectDifferenceType.Different);
+
+ differences.Tables[0].Columns[10].DefaultConstraint.Source.Should().BeSameAs(differences.Tables[0].Source.Columns[12].DefaultConstraint);
+ differences.Tables[0].Columns[10].DefaultConstraint.Target.Should().BeSameAs(differences.Tables[0].Target.Columns[12].DefaultConstraint);
+ differences.Tables[0].Columns[10].DefaultConstraint.Type.Should().Be(SqlObjectDifferenceType.Different);
+ differences.Tables[0].Columns[10].DefaultConstraint.Properties.Should().HaveCount(1);
+ differences.Tables[0].Columns[10].DefaultConstraint.Properties[0].Name.Should().Be("Name");
+ differences.Tables[0].Columns[10].DefaultConstraint.Properties[0].Source.Should().Be("DF_TableDifference_ColumnWithOtherDefaultConstraintName");
+ differences.Tables[0].Columns[10].DefaultConstraint.Properties[0].Target.Should().Be("DF_TableDifference_WrongName");
+ differences.Tables[0].Columns[10].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[12]);
+ differences.Tables[0].Columns[10].Target.Should().BeSameAs(differences.Tables[0].Target.Columns[12]);
+ differences.Tables[0].Columns[10].Type.Should().Be(SqlObjectDifferenceType.Different);
+
+ differences.Tables[0].Columns[11].DefaultConstraint.Should().BeNull();
+ differences.Tables[0].Columns[11].Source.Should().BeSameAs(differences.Tables[0].Source.Columns[8]);
+ differences.Tables[0].Columns[11].Target.Should().BeNull();
+ differences.Tables[0].Columns[11].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
// Tables / Foreign keys
differences.Tables[0].Source.ForeignKeys.Should().HaveCount(1);
@@ -542,7 +684,6 @@ public async Task CompareAsync()
differences.Tables[0].PrimaryKey.Columns[1].Source.Should().BeSameAs(differences.Tables[0].Source.PrimaryKey.Columns[0]);
differences.Tables[0].PrimaryKey.Columns[1].Target.Should().BeSameAs(differences.Tables[0].Target.PrimaryKey.Columns[1]);
differences.Tables[0].PrimaryKey.Columns[1].Type.Should().Be(SqlObjectDifferenceType.Different);
-
differences.Tables[0].PrimaryKey.Properties.Should().HaveCount(1);
differences.Tables[0].PrimaryKey.Properties[0].Name.Should().Be("Type");
differences.Tables[0].PrimaryKey.Properties[0].Source.Should().Be("NONCLUSTERED");
@@ -625,6 +766,28 @@ public async Task CompareAsync()
differences.Tables[1].Target.Columns[0].Precision.Should().Be(10);
differences.Tables[1].Target.Columns[0].Scale.Should().Be(0);
differences.Tables[1].Target.Columns[0].TypeName.Should().Be("int");
+ differences.Tables[1].Target.Columns[1].CollationName.Should().Be("SQL_Latin1_General_CP1_CI_AS");
+ differences.Tables[1].Target.Columns[1].ComputedExpression.Should().BeNull();
+ differences.Tables[1].Target.Columns[1].IsComputed.Should().BeFalse();
+ differences.Tables[1].Target.Columns[1].IsIdentity.Should().BeFalse();
+ differences.Tables[1].Target.Columns[1].IsNullable.Should().BeTrue();
+ differences.Tables[1].Target.Columns[1].MaxLength.Should().Be(50);
+ differences.Tables[1].Target.Columns[1].Name.Should().Be("TargetName");
+ differences.Tables[1].Target.Columns[1].Position.Should().Be(2);
+ differences.Tables[1].Target.Columns[1].Precision.Should().Be(0);
+ differences.Tables[1].Target.Columns[1].Scale.Should().Be(0);
+ differences.Tables[1].Target.Columns[1].TypeName.Should().Be("varchar");
+ differences.Tables[1].Target.Columns[2].CollationName.Should().BeNull();
+ differences.Tables[1].Target.Columns[2].ComputedExpression.Should().BeNull();
+ differences.Tables[1].Target.Columns[2].IsComputed.Should().BeFalse();
+ differences.Tables[1].Target.Columns[2].IsIdentity.Should().BeFalse();
+ differences.Tables[1].Target.Columns[2].IsNullable.Should().BeFalse();
+ differences.Tables[1].Target.Columns[2].MaxLength.Should().Be(4);
+ differences.Tables[1].Target.Columns[2].Name.Should().Be("TargetForeignKeyId");
+ differences.Tables[1].Target.Columns[2].Position.Should().Be(3);
+ differences.Tables[1].Target.Columns[2].Precision.Should().Be(10);
+ differences.Tables[1].Target.Columns[2].Scale.Should().Be(0);
+ differences.Tables[1].Target.Columns[2].TypeName.Should().Be("int");
differences.Tables[1].Target.ForeignKeys.Should().HaveCount(1);
differences.Tables[1].Target.ForeignKeys[0].Columns.Should().HaveCount(1);
differences.Tables[1].Target.ForeignKeys[0].Columns[0].Name.Should().Be("TargetForeignKeyId");
@@ -666,13 +829,28 @@ public async Task CompareAsync()
differences.Tables[1].Type.Should().Be(SqlObjectDifferenceType.MissingInSource);
differences.Tables[2].Columns.Should().BeEmpty();
- differences.Tables[2].Indexes.Should().BeEmpty();
- differences.Tables[2].PrimaryKey.Should().BeNull();
+ differences.Tables[2].Indexes.Should().HaveCount(2);
+ differences.Tables[2].Indexes[0].Columns.Should().BeEmpty();
+ differences.Tables[2].Indexes[0].IncludedColumns.Should().BeEmpty();
+ differences.Tables[2].Indexes[0].Properties.Should().BeEmpty();
+ differences.Tables[2].Indexes[0].Source.Should().BeNull();
+ differences.Tables[2].Indexes[0].Target.Should().BeSameAs(differences.Tables[2].Target.Indexes[0]);
+ differences.Tables[2].Indexes[0].Type.Should().Be(SqlObjectDifferenceType.MissingInSource);
+ differences.Tables[2].Indexes[1].Columns.Should().BeEmpty();
+ differences.Tables[2].Indexes[1].IncludedColumns.Should().BeEmpty();
+ differences.Tables[2].Indexes[1].Properties.Should().BeEmpty();
+ differences.Tables[2].Indexes[1].Source.Should().BeSameAs(differences.Tables[2].Source.Indexes[0]);
+ differences.Tables[2].Indexes[1].Target.Should().BeNull();
+ differences.Tables[2].Indexes[1].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
+ differences.Tables[2].PrimaryKey.Source.Should().BeSameAs(differences.Tables[2].Source.PrimaryKey);
+ differences.Tables[2].PrimaryKey.Target.Should().BeSameAs(differences.Tables[2].Target.PrimaryKey);
+ differences.Tables[2].PrimaryKey.Properties.Should().HaveCount(1);
+ differences.Tables[2].PrimaryKey.Properties[0].Name.Should().Be("Name");
+ differences.Tables[2].PrimaryKey.Properties[0].Source.Should().Be("PK_TableWithDifferentPrimaryKey_Source");
+ differences.Tables[2].PrimaryKey.Properties[0].Target.Should().Be("PK_TableWithDifferentPrimaryKey_Target");
differences.Tables[2].UniqueConstraints.Should().BeEmpty();
- differences.Tables[2].Source.CheckConstraints.Should().HaveCount(1);
- differences.Tables[2].Source.CheckConstraints[0].Name.Should().Be("CheckConstraintSource");
- differences.Tables[2].Source.CheckConstraints[0].Code.Should().Be("([Id]>(0))");
- differences.Tables[2].Source.Columns.Should().HaveCount(3);
+ differences.Tables[2].Source.CheckConstraints.Should().BeEmpty();
+ differences.Tables[2].Source.Columns.Should().HaveCount(1);
differences.Tables[2].Source.Columns[0].CollationName.Should().BeNull();
differences.Tables[2].Source.Columns[0].ComputedExpression.Should().BeNull();
differences.Tables[2].Source.Columns[0].IsComputed.Should().BeFalse();
@@ -684,45 +862,111 @@ public async Task CompareAsync()
differences.Tables[2].Source.Columns[0].Precision.Should().Be(10);
differences.Tables[2].Source.Columns[0].Scale.Should().Be(0);
differences.Tables[2].Source.Columns[0].TypeName.Should().Be("int");
- differences.Tables[2].Source.Indexes.Should().HaveCount(2);
+ differences.Tables[2].Source.Indexes.Should().HaveCount(1);
differences.Tables[2].Source.Indexes[0].Columns.Should().HaveCount(1);
- differences.Tables[2].Source.Indexes[0].Columns[0].Name.Should().Be("SourceName");
+ differences.Tables[2].Source.Indexes[0].Columns[0].Name.Should().Be("Id");
differences.Tables[2].Source.Indexes[0].Columns[0].Position.Should().Be(1);
- differences.Tables[2].Source.Indexes[0].Filter.Should().Be("([SourceName]='')");
- differences.Tables[2].Source.Indexes[0].IncludedColumns.Should().HaveCount(1);
- differences.Tables[2].Source.Indexes[0].IncludedColumns[0].Name.Should().Be("SourceForeignKeyId");
- differences.Tables[2].Source.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
- differences.Tables[2].Source.Indexes[0].IsUnique.Should().BeFalse();
- differences.Tables[2].Source.Indexes[0].Name.Should().Be("IndexSource");
- differences.Tables[2].Source.Indexes[1].Columns.Should().HaveCount(1);
- differences.Tables[2].Source.Indexes[1].Columns[0].Name.Should().Be("Id");
- differences.Tables[2].Source.Indexes[1].Columns[0].Position.Should().Be(1);
- differences.Tables[2].Source.Indexes[1].Filter.Should().BeNull();
- differences.Tables[2].Source.Indexes[1].IncludedColumns.Should().HaveCount(0);
- differences.Tables[2].Source.ForeignKeys.Should().HaveCount(1);
- differences.Tables[2].Source.ForeignKeys[0].Columns.Should().HaveCount(1);
- differences.Tables[2].Source.ForeignKeys[0].Columns[0].Name.Should().Be("SourceForeignKeyId");
- differences.Tables[2].Source.ForeignKeys[0].Columns[0].Position.Should().Be(1);
- differences.Tables[2].Source.ForeignKeys[0].DeleteAction.Should().Be("NO_ACTION");
- differences.Tables[2].Source.ForeignKeys[0].Name.Should().Be("ForeignKeySource");
- differences.Tables[2].Source.ForeignKeys[0].ReferencedTable.Should().Be("ReferencedTable");
- differences.Tables[2].Source.ForeignKeys[0].UpdateAction.Should().Be("NO_ACTION");
- differences.Tables[2].Source.Name.Should().Be("TableSource");
+ differences.Tables[2].Source.Indexes[0].Filter.Should().BeNull();
+ differences.Tables[2].Source.Indexes[0].IncludedColumns.Should().BeEmpty();
+ differences.Tables[2].Source.Indexes[0].IsUnique.Should().BeTrue();
+ differences.Tables[2].Source.Indexes[0].Name.Should().Be("PK_TableWithDifferentPrimaryKey_Source");
+ differences.Tables[2].Source.ForeignKeys.Should().BeEmpty();
+ differences.Tables[2].Source.Name.Should().Be("TableWithDifferentPrimaryKey");
differences.Tables[2].Source.Schema.Should().Be("dbo");
- differences.Tables[2].Source.PrimaryKey.Name.Should().Be("PrimaryKeySource");
+ differences.Tables[2].Source.PrimaryKey.Name.Should().Be("PK_TableWithDifferentPrimaryKey_Source");
differences.Tables[2].Source.PrimaryKey.Type.Should().Be("CLUSTERED");
- differences.Tables[2].Source.Triggers.Should().HaveCount(1);
- differences.Tables[2].Source.Triggers[0].Name.Should().Be("TriggerSource");
- differences.Tables[2].Source.Triggers[0].Code.Should().Be("CREATE TRIGGER [TriggerSource]\r\n\tON [dbo].[TableSource]\r\n\tFOR DELETE, INSERT, UPDATE\r\n\tAS\r\n\tBEGIN\r\n\t\tSET NOCOUNT ON\r\n\tEND");
- differences.Tables[2].Source.Triggers[0].IsInsteadOfTrigger.Should().BeFalse();
- differences.Tables[2].Source.UniqueConstraints.Should().HaveCount(1);
- differences.Tables[2].Source.UniqueConstraints[0].Columns.Should().HaveCount(1);
- differences.Tables[2].Source.UniqueConstraints[0].Columns[0].Name.Should().Be("Id");
- differences.Tables[2].Source.UniqueConstraints[0].Columns[0].Position.Should().Be(1);
- differences.Tables[2].Source.UniqueConstraints[0].Name.Should().Be("UniqueConstraintSource");
- differences.Tables[2].Source.UniqueConstraints[0].Type.Should().Be("NONCLUSTERED");
+ differences.Tables[2].Source.Triggers.Should().BeEmpty();
+ differences.Tables[2].Source.UniqueConstraints.Should().BeEmpty();
+ differences.Tables[2].Target.CheckConstraints.Should().BeEmpty();
+ differences.Tables[2].Target.Columns.Should().HaveCount(1);
+ differences.Tables[2].Target.Columns[0].CollationName.Should().BeNull();
+ differences.Tables[2].Target.Columns[0].ComputedExpression.Should().BeNull();
+ differences.Tables[2].Target.Columns[0].IsComputed.Should().BeFalse();
+ differences.Tables[2].Target.Columns[0].IsIdentity.Should().BeFalse();
+ differences.Tables[2].Target.Columns[0].IsNullable.Should().BeFalse();
+ differences.Tables[2].Target.Columns[0].MaxLength.Should().Be(4);
+ differences.Tables[2].Target.Columns[0].Name.Should().Be("Id");
+ differences.Tables[2].Target.Columns[0].Position.Should().Be(1);
+ differences.Tables[2].Target.Columns[0].Precision.Should().Be(10);
+ differences.Tables[2].Target.Columns[0].Scale.Should().Be(0);
+ differences.Tables[2].Target.Columns[0].TypeName.Should().Be("int");
+ differences.Tables[2].Target.Indexes.Should().HaveCount(1);
+ differences.Tables[2].Target.Indexes[0].Columns.Should().HaveCount(1);
+ differences.Tables[2].Target.Indexes[0].Columns[0].Name.Should().Be("Id");
+ differences.Tables[2].Target.Indexes[0].Columns[0].Position.Should().Be(1);
+ differences.Tables[2].Target.Indexes[0].Filter.Should().BeNull();
+ differences.Tables[2].Target.Indexes[0].IncludedColumns.Should().BeEmpty();
+ differences.Tables[2].Target.Indexes[0].IsUnique.Should().BeTrue();
+ differences.Tables[2].Target.Indexes[0].Name.Should().Be("PK_TableWithDifferentPrimaryKey_Target");
+ differences.Tables[2].Target.ForeignKeys.Should().BeEmpty();
+ differences.Tables[2].Target.Name.Should().Be("TableWithDifferentPrimaryKey");
+ differences.Tables[2].Target.Schema.Should().Be("dbo");
+ differences.Tables[2].Target.PrimaryKey.Name.Should().Be("PK_TableWithDifferentPrimaryKey_Target");
+ differences.Tables[2].Target.PrimaryKey.Type.Should().Be("CLUSTERED");
+ differences.Tables[2].Target.Triggers.Should().BeEmpty();
+ differences.Tables[2].Target.UniqueConstraints.Should().BeEmpty();
differences.Tables[2].Triggers.Should().BeEmpty();
- differences.Tables[2].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
+ differences.Tables[2].Type.Should().Be(SqlObjectDifferenceType.Different);
+
+ differences.Tables[3].Columns.Should().BeEmpty();
+ differences.Tables[3].Indexes.Should().BeEmpty();
+ differences.Tables[3].PrimaryKey.Should().BeNull();
+ differences.Tables[3].UniqueConstraints.Should().BeEmpty();
+ differences.Tables[3].Source.CheckConstraints.Should().HaveCount(1);
+ differences.Tables[3].Source.CheckConstraints[0].Name.Should().Be("CheckConstraintSource");
+ differences.Tables[3].Source.CheckConstraints[0].Code.Should().Be("([Id]>(0))");
+ differences.Tables[3].Source.Columns.Should().HaveCount(3);
+ differences.Tables[3].Source.Columns[0].CollationName.Should().BeNull();
+ differences.Tables[3].Source.Columns[0].ComputedExpression.Should().BeNull();
+ differences.Tables[3].Source.Columns[0].IsComputed.Should().BeFalse();
+ differences.Tables[3].Source.Columns[0].IsIdentity.Should().BeFalse();
+ differences.Tables[3].Source.Columns[0].IsNullable.Should().BeFalse();
+ differences.Tables[3].Source.Columns[0].MaxLength.Should().Be(4);
+ differences.Tables[3].Source.Columns[0].Name.Should().Be("Id");
+ differences.Tables[3].Source.Columns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.Columns[0].Precision.Should().Be(10);
+ differences.Tables[3].Source.Columns[0].Scale.Should().Be(0);
+ differences.Tables[3].Source.Columns[0].TypeName.Should().Be("int");
+ differences.Tables[3].Source.Indexes.Should().HaveCount(2);
+ differences.Tables[3].Source.Indexes[0].Columns.Should().HaveCount(1);
+ differences.Tables[3].Source.Indexes[0].Columns[0].Name.Should().Be("SourceName");
+ differences.Tables[3].Source.Indexes[0].Columns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.Indexes[0].Filter.Should().Be("([SourceName]='')");
+ differences.Tables[3].Source.Indexes[0].IncludedColumns.Should().HaveCount(1);
+ differences.Tables[3].Source.Indexes[0].IncludedColumns[0].Name.Should().Be("SourceForeignKeyId");
+ differences.Tables[3].Source.Indexes[0].IncludedColumns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.Indexes[0].IsUnique.Should().BeFalse();
+ differences.Tables[3].Source.Indexes[0].Name.Should().Be("IndexSource");
+ differences.Tables[3].Source.Indexes[1].Columns.Should().HaveCount(1);
+ differences.Tables[3].Source.Indexes[1].Columns[0].Name.Should().Be("Id");
+ differences.Tables[3].Source.Indexes[1].Columns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.Indexes[1].Filter.Should().BeNull();
+ differences.Tables[3].Source.Indexes[1].IncludedColumns.Should().HaveCount(0);
+ differences.Tables[3].Source.ForeignKeys.Should().HaveCount(1);
+ differences.Tables[3].Source.ForeignKeys[0].Columns.Should().HaveCount(1);
+ differences.Tables[3].Source.ForeignKeys[0].Columns[0].Name.Should().Be("SourceForeignKeyId");
+ differences.Tables[3].Source.ForeignKeys[0].Columns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.ForeignKeys[0].DeleteAction.Should().Be("NO_ACTION");
+ differences.Tables[3].Source.ForeignKeys[0].Name.Should().Be("ForeignKeySource");
+ differences.Tables[3].Source.ForeignKeys[0].ReferencedTable.Should().Be("ReferencedTable");
+ differences.Tables[3].Source.ForeignKeys[0].UpdateAction.Should().Be("NO_ACTION");
+ differences.Tables[3].Source.Name.Should().Be("TableSource");
+ differences.Tables[3].Source.Schema.Should().Be("dbo");
+ differences.Tables[3].Source.PrimaryKey.Name.Should().Be("PrimaryKeySource");
+ differences.Tables[3].Source.PrimaryKey.Type.Should().Be("CLUSTERED");
+ differences.Tables[3].Source.Triggers.Should().HaveCount(1);
+ differences.Tables[3].Source.Triggers[0].Name.Should().Be("TriggerSource");
+ differences.Tables[3].Source.Triggers[0].Code.Should().Be("CREATE TRIGGER [TriggerSource]\r\n\tON [dbo].[TableSource]\r\n\tFOR DELETE, INSERT, UPDATE\r\n\tAS\r\n\tBEGIN\r\n\t\tSET NOCOUNT ON\r\n\tEND");
+ differences.Tables[3].Source.Triggers[0].IsInsteadOfTrigger.Should().BeFalse();
+ differences.Tables[3].Source.UniqueConstraints.Should().HaveCount(1);
+ differences.Tables[3].Source.UniqueConstraints[0].Columns.Should().HaveCount(1);
+ differences.Tables[3].Source.UniqueConstraints[0].Columns[0].Name.Should().Be("Id");
+ differences.Tables[3].Source.UniqueConstraints[0].Columns[0].Position.Should().Be(1);
+ differences.Tables[3].Source.UniqueConstraints[0].Name.Should().Be("UniqueConstraintSource");
+ differences.Tables[3].Source.UniqueConstraints[0].Type.Should().Be("NONCLUSTERED");
+ differences.Tables[3].Target.Should().BeNull();
+ differences.Tables[3].Triggers.Should().BeEmpty();
+ differences.Tables[3].Type.Should().Be(SqlObjectDifferenceType.MissingInTarget);
// UserTypes
differences.UserTypes.Should().HaveCount(3);
diff --git a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseExtensionsTest.cs b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseExtensionsTest.cs
index ffdfdde..4718aec 100644
--- a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseExtensionsTest.cs
+++ b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseExtensionsTest.cs
@@ -219,5 +219,134 @@ GO 10
table.Rows[0]["Id"].Should().Be(10);
}
+
+ [Fact]
+ public async Task ExecuteScriptAsync_String()
+ {
+ var server = new SqlServer(ConnectionString);
+
+ var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
+
+ await database.ExecuteScriptAsync(@"
+ CREATE TABLE TableTest
+ (
+ Id INT NOT NULL
+ )
+
+ GO
+ GO
+
+ INSERT INTO [TableTest] ([Id]) VALUES (0)
+
+ GO
+ UPDATE [TableTest]
+ SET [Id] = [Id] + 1
+
+ GO 10");
+
+ var table = await database.ExecuteQueryAsync("SELECT * FROM [TableTest]");
+
+ table.Rows.Should().HaveCount(1);
+
+ table.Rows[0]["Id"].Should().Be(10);
+ }
+
+ [Fact]
+ public async Task ExecuteScriptAsync_String_WithEmptyLinesAtTheEnd()
+ {
+ var server = new SqlServer(ConnectionString);
+
+ var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
+
+ await database.ExecuteScriptAsync(@"
+ CREATE TABLE TableTest
+ (
+ Id INT NOT NULL
+ )
+
+ GO
+ GO
+
+ INSERT INTO [TableTest] ([Id]) VALUES (0)
+
+ GO
+ UPDATE [TableTest]
+ SET [Id] = [Id] + 1
+
+ GO 10
+
+ ");
+
+ var table = await database.ExecuteQueryAsync("SELECT * FROM [TableTest]");
+
+ table.Rows.Should().HaveCount(1);
+
+ table.Rows[0]["Id"].Should().Be(10);
+ }
+
+ [Fact]
+ public async Task ExecuteScriptAsync_StringReader()
+ {
+ var server = new SqlServer(ConnectionString);
+
+ var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
+
+ await database.ExecuteScriptAsync(new StringReader(@"
+ CREATE TABLE TableTest
+ (
+ Id INT NOT NULL
+ )
+
+ GO
+ GO
+
+ INSERT INTO [TableTest] ([Id]) VALUES (0)
+
+ GO
+ UPDATE [TableTest]
+ SET [Id] = [Id] + 1
+
+ GO 10"));
+
+ var table = await database.ExecuteQueryAsync("SELECT * FROM [TableTest]");
+
+ table.Rows.Should().HaveCount(1);
+
+ table.Rows[0]["Id"].Should().Be(10);
+ }
+
+ [Fact]
+ public async Task ExecuteScriptAsync_StringReader_WithEmptyLinesAtTheEnd()
+ {
+ var server = new SqlServer(ConnectionString);
+
+ var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
+
+ await database.ExecuteScriptAsync(new StringReader(@"
+ CREATE TABLE TableTest
+ (
+ Id INT NOT NULL
+ )
+
+ GO
+ GO
+
+ INSERT INTO [TableTest] ([Id]) VALUES (0)
+
+ GO
+ UPDATE [TableTest]
+ SET [Id] = [Id] + 1
+
+ GO 10
+
+
+ "));
+
+ var table = await database.ExecuteQueryAsync("SELECT * FROM [TableTest]");
+
+ table.Rows.Should().HaveCount(1);
+
+ table.Rows[0]["Id"].Should().Be(10);
+ }
}
}
\ No newline at end of file
diff --git a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseInitializerTest.cs b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseInitializerTest.cs
index 57da907..44c72e0 100644
--- a/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseInitializerTest.cs
+++ b/tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseInitializerTest.cs
@@ -66,5 +66,47 @@ public void Test2()
// Insert a row which should not be use in other tests.
this.database.InsertInto("MyTable", new { Id = 99, Name = "Should not be here for the next test" });
}
+
+ [Fact]
+ public async Task Test1Async()
+ {
+ var currentUser = await this.database.ExecuteQueryAsync("SELECT SUSER_NAME()");
+ currentUser.Rows[0][0].Should().Be($"{Environment.UserDomainName}\\{Environment.UserName}");
+
+ // Check the constructor has been called
+ var table = await this.database.ExecuteQueryAsync("SELECT * FROM MyTable");
+
+ table.Rows.Should().HaveCount(2);
+
+ table.Rows[0]["Id"].Should().Be(1);
+ table.Rows[0]["Name"].Should().Be("Name 1");
+
+ table.Rows[1]["Id"].Should().Be(2);
+ table.Rows[1]["Name"].Should().Be("Name 2");
+
+ // Insert a row which should not be use in other tests.
+ await this.database.InsertIntoAsync("MyTable", new { Id = 99, Name = "Should not be here for the next test" });
+ }
+
+ [Fact]
+ public async Task Test2Async()
+ {
+ var currentUser = await this.database.ExecuteQueryAsync("SELECT SUSER_NAME()");
+ currentUser.Rows[0][0].Should().Be($"{Environment.UserDomainName}\\{Environment.UserName}");
+
+ // Check the constructor has been called
+ var table = await this.database.ExecuteQueryAsync("SELECT * FROM MyTable");
+
+ table.Rows.Should().HaveCount(2);
+
+ table.Rows[0]["Id"].Should().Be(1);
+ table.Rows[0]["Name"].Should().Be("Name 1");
+
+ table.Rows[1]["Id"].Should().Be(2);
+ table.Rows[1]["Name"].Should().Be("Name 2");
+
+ // Insert a row which should not be use in other tests.
+ await this.database.InsertIntoAsync("MyTable", new { Id = 99, Name = "Should not be here for the next test" });
+ }
}
}
\ No newline at end of file
diff --git a/tests/Testing.Databases.SqlServer.Tests/SqlServerTest.cs b/tests/Testing.Databases.SqlServer.Tests/SqlServerTest.cs
index 09c53c4..e4824da 100644
--- a/tests/Testing.Databases.SqlServer.Tests/SqlServerTest.cs
+++ b/tests/Testing.Databases.SqlServer.Tests/SqlServerTest.cs
@@ -6,8 +6,11 @@
namespace PosInformatique.Testing.Databases.SqlServer.Tests
{
+ [Collection("PosInformatique.Testing.Databases.SqlServer.Tests")]
public class SqlServerTest
{
+ private const string ConnectionString = $"Data Source=(localDB)\\posinfo-tests; Initial Catalog={nameof(SqlServerTest)}; Integrated Security=True";
+
[Theory]
[InlineData("Data Source=TheServer; Initial Catalog=TheDB; User ID=TheID; Password=ThePassword", "Data Source=TheServer;Initial Catalog=master;User ID=TheID;Password=ThePassword")]
[InlineData("Data Source=TheServer; Initial Catalog=TheDB; Integrated Security=True", "Data Source=TheServer;Initial Catalog=master;Integrated Security=True")]
@@ -18,5 +21,24 @@ public void Constructor(string connectionString, string expectedMasterConnection
server.Master.ConnectionString.Should().Be(expectedMasterConnectionString);
server.Master.Server.Should().BeSameAs(server);
}
+
+ [Fact]
+ public async Task CreateAndDeleteAsync()
+ {
+ var server = new SqlServer(ConnectionString);
+
+ var database = await server.CreateEmptyDatabaseAsync("CreateAndDeleteDB", CancellationToken.None);
+
+ database.ConnectionString.Should().Be("Data Source=(localDB)\\posinfo-tests;Initial Catalog=CreateAndDeleteDB;Integrated Security=True");
+
+ var table = await server.Master.ExecuteQueryAsync("SELECT * FROM [sys].[databases] WHERE [name] = 'CreateAndDeleteDB'");
+ table.Rows.Should().HaveCount(1);
+
+ // Delete the database
+ await server.DeleteDatabaseAsync("CreateAndDeleteDB", CancellationToken.None);
+
+ table = await server.Master.ExecuteQueryAsync("SELECT * FROM [sys].[databases] WHERE [name] = 'CreateAndDeleteDB'");
+ table.Rows.Should().BeEmpty();
+ }
}
}
\ No newline at end of file