Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ This test:
```cs
await Verify(connection);
```
<sup><a href='/src/Tests/Tests.cs#L317-L321' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L316-L320' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file:
Expand All @@ -69,7 +69,7 @@ await Verify(connection)
// include only tables and views
.SchemaIncludes(DbObjects.Tables | DbObjects.Views);
```
<sup><a href='/src/Tests/Tests.cs#L683-L689' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L682-L688' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Available values:
Expand Down Expand Up @@ -107,7 +107,7 @@ await Verify(connection)
_ => _ is TableViewBase ||
_.Name == "MyTrigger");
```
<sup><a href='/src/Tests/Tests.cs#L708-L716' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L707-L715' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand All @@ -129,7 +129,7 @@ command.CommandText = "select Value from MyTable";
var value = await command.ExecuteScalarAsync();
await Verify(value!);
```
<sup><a href='/src/Tests/Tests.cs#L492-L502' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L491-L501' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Will result in the following verified file:
Expand Down Expand Up @@ -184,7 +184,7 @@ await Verify(
sqlEntries = entries
});
```
<sup><a href='/src/Tests/Tests.cs#L569-L599' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L568-L598' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down Expand Up @@ -212,7 +212,7 @@ var sqlErrorsViaType = entries
.Select(_ => _.Data)
.OfType<ErrorEntry>();
```
<sup><a href='/src/Tests/Tests.cs#L625-L644' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/Tests.cs#L624-L643' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
21 changes: 21 additions & 0 deletions src/Tests/Tests.SchemaFromOpenConnection.verified.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Tables

### MyTable

```sql
CREATE TABLE [dbo].[MyTable](
[Value] [int] NULL
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [MyIndex] ON [dbo].[MyTable]
(
[Value] ASC
) ON [PRIMARY]

CREATE TRIGGER MyTrigger
ON MyTable
AFTER UPDATE
AS RAISERROR ('Notify Customer Relations', 16, 10);

ALTER TABLE [dbo].[MyTable] ENABLE TRIGGER [MyTrigger]
```
24 changes: 19 additions & 5 deletions src/Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ static Tests() =>
"VerifySqlServer",
connection =>
{
var serverConnection = new ServerConnection
{
ConnectionString = connection.ConnectionString,
};
var serverConnection = new ServerConnection();
SqlScriptBuilder.SqlConnectionObjectField.SetValue(serverConnection, connection);
serverConnection.NonPooledConnection = true;
var server = new Server(serverConnection);
server.ConnectionContext.ExecuteNonQuery(
"""
Expand Down Expand Up @@ -854,4 +853,19 @@ await Verify(connection)
.SchemaIncludes(DbObjects.Tables | DbObjects.Views)
.SchemaFilter(_ => _.Name is "MyTable" or "MyView" or "MyProcedure");
}
}

// Verifies the workaround for SMO 181.15.0 + SqlClient 7.0 TypeLoadException.
// SMO's ServerConnection(SqlConnection) constructor references SqlAuthenticationMethod
// which moved from Microsoft.Data.SqlClient to Extensions.Abstractions in SqlClient 7.0.
// The fix avoids that constructor by using reflection to set the SqlConnection directly.
[Test]
public async Task SchemaFromOpenConnection()
{
await using var database = await sqlInstance.Build();
await using var connection = new SqlConnection(database.ConnectionString);
await connection.OpenAsync();
await Verify(connection)
.SchemaFilter(_ => _.Name == "MyTable")
.SchemaIncludes(DbObjects.Tables);
}
}
2 changes: 2 additions & 0 deletions src/Verify.SqlServer/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
global using System.Data.Common;
global using System.Data.SqlTypes;
global using System.Globalization;
global using System.Text.RegularExpressions;
global using Microsoft.Data.SqlClient;
global using Microsoft.Extensions.DiagnosticAdapter;
global using Microsoft.SqlServer.Management.Common;
global using Microsoft.SqlServer.Management.Smo;
global using Microsoft.SqlServer.TransactSql.ScriptDom;
global using VerifyTests.SqlServer;
2 changes: 0 additions & 2 deletions src/Verify.SqlServer/SchemaValidation/SchemaSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.SqlServer.Management.Smo;

class SchemaSettings
{
public DbObjects Includes { get; set; } = DbObjects.All;
Expand Down
22 changes: 18 additions & 4 deletions src/Verify.SqlServer/SchemaValidation/SqlScriptBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Management.Smo;

class SqlScriptBuilder(SchemaSettings settings)
{
// TODO: when Microsoft.Data.SqlClient 7.0.1 adds TypeForwardedTo for SqlAuthenticationMethod,
// revert to using new ServerConnection(SqlConnection) and remove this reflection workaround.
//
// SMO 181.15.0 ServerConnection(SqlConnection) constructor calls InitFromSqlConnection
// which references SqlAuthenticationMethod — a type moved from Microsoft.Data.SqlClient
// to Microsoft.Data.SqlClient.Extensions.Abstractions in SqlClient 7.0. The CLR can't
// resolve the type in the original assembly, causing a TypeLoadException.
//
// Workaround: construct ServerConnection() with default constructor (no InitFromSqlConnection),
// then set the internal m_SqlConnectionObject field via reflection to reuse the open connection.
// SMO detects the connection is already open and uses it directly.
internal static readonly FieldInfo SqlConnectionObjectField =
typeof(ConnectionManager).GetField("m_SqlConnectionObject", BindingFlags.NonPublic | BindingFlags.Instance) ??
throw new("Could not find field m_SqlConnectionObject on ConnectionManager. The SMO internals may have changed.");

static Dictionary<string, string> tableSettingsToScrubLookup;

static SqlScriptBuilder()
Expand Down Expand Up @@ -33,10 +45,12 @@ public string BuildContent(SqlConnection connection)
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
var serverConnection = new ServerConnection
{
NonPooledConnection = true,
ConnectionString = connection.ConnectionString,
};
try
{
SqlConnectionObjectField.SetValue(serverConnection, connection);
var server = new Server(serverConnection);
return BuildContent(server, builder);
}
Expand Down Expand Up @@ -240,4 +254,4 @@ script is
"SET QUOTED_IDENTIFIER OFF" or
"SET ANSI_PADDING ON" or
"SET ANSI_PADDING OFF";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.SqlServer.Management.Smo;

namespace VerifyTests;

public static partial class VerifySettingsSqlExtensions
Expand Down Expand Up @@ -81,4 +79,4 @@ internal static SchemaSettings GetSchemaSettings(this IReadOnlyDictionary<string

// Shared instance is safe: callers only read from it, never mutate
static SchemaSettings defaultSettings = new();
}
}
1 change: 1 addition & 0 deletions src/Verify.SqlServer/Verify.SqlServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<TargetFrameworks>net48;net8.0;net9.0;net10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000f0a8e4bf1639dce01be6592384e7dfc621915b7759fb5cee42ec5d351bcc43460432da1659ee618ca6cab6b8b8e56a5deb5d4ee1a49783d5c2690752502d31ccbfee9b2c697e20359b55ad100cc9370c8e983fd9496f01d761a060d0435bac7243b1832ba95757aa5adbb67df38c213d717b6751e1217cea9fa5c61e9b799dd" />
<PackageReference Include="Microsoft.Data.SqlClient" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" />
<PackageReference Include="Microsoft.SqlServer.TransactSql.ScriptDom" />
Expand Down
Loading