diff --git a/All.sln b/All.sln
index 8d3e4962940..d563d5774aa 100644
--- a/All.sln
+++ b/All.sln
@@ -108,6 +108,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFCore.Benchmarks", "benchm
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EF.Benchmarks.Shared", "benchmark\EF.Benchmarks.Shared\EF.Benchmarks.Shared.csproj", "{BFC26566-4C6D-4904-A559-8FFE09369901}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.Sqlite.e_sqlcipher.Tests", "test\Microsoft.Data.Sqlite.Tests\Microsoft.Data.Sqlite.e_sqlcipher.Tests.csproj", "{7B598E0C-B8E2-4F1F-B53C-ED84178E65BE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Data.Sqlite.winsqlite3.Tests", "test\Microsoft.Data.Sqlite.Tests\Microsoft.Data.Sqlite.winsqlite3.Tests.csproj", "{B163761D-FB4A-4C80-BAB9-01905E1351EF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -282,6 +286,14 @@ Global
{BFC26566-4C6D-4904-A559-8FFE09369901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFC26566-4C6D-4904-A559-8FFE09369901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFC26566-4C6D-4904-A559-8FFE09369901}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B598E0C-B8E2-4F1F-B53C-ED84178E65BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B598E0C-B8E2-4F1F-B53C-ED84178E65BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B598E0C-B8E2-4F1F-B53C-ED84178E65BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B598E0C-B8E2-4F1F-B53C-ED84178E65BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B163761D-FB4A-4C80-BAB9-01905E1351EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B163761D-FB4A-4C80-BAB9-01905E1351EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B163761D-FB4A-4C80-BAB9-01905E1351EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B163761D-FB4A-4C80-BAB9-01905E1351EF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -329,6 +341,8 @@ Global
{678AB38D-B27C-4690-A3F9-2D2488391658} = {293B4F79-3CB9-402A-A74C-B8108C41A7CF}
{2642F4F0-69BE-4C43-94B7-B298FEC87D89} = {293B4F79-3CB9-402A-A74C-B8108C41A7CF}
{BFC26566-4C6D-4904-A559-8FFE09369901} = {293B4F79-3CB9-402A-A74C-B8108C41A7CF}
+ {7B598E0C-B8E2-4F1F-B53C-ED84178E65BE} = {258D5057-81B9-40EC-A872-D21E27452749}
+ {B163761D-FB4A-4C80-BAB9-01905E1351EF} = {258D5057-81B9-40EC-A872-D21E27452749}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {285A5EB4-BCF4-40EB-B9E1-DF6DBCB5E705}
diff --git a/Microsoft.Data.Sqlite.slnf b/Microsoft.Data.Sqlite.slnf
index 0ea10736dc3..02eee0ff2f8 100644
--- a/Microsoft.Data.Sqlite.slnf
+++ b/Microsoft.Data.Sqlite.slnf
@@ -4,7 +4,9 @@
"projects": [
"src\\Microsoft.Data.Sqlite.Core\\Microsoft.Data.Sqlite.Core.csproj",
"src\\Microsoft.Data.Sqlite\\Microsoft.Data.Sqlite.csproj",
- "test\\Microsoft.Data.Sqlite.Tests\\Microsoft.Data.Sqlite.Tests.csproj"
+ "test\\Microsoft.Data.Sqlite.Tests\\Microsoft.Data.Sqlite.Tests.csproj",
+ "test\\Microsoft.Data.Sqlite.Tests\\Microsoft.Data.Sqlite.e_sqlcipher.Tests.csproj",
+ "test\\Microsoft.Data.Sqlite.Tests\\Microsoft.Data.Sqlite.winsqlite3.Tests.csproj"
]
}
}
\ No newline at end of file
diff --git a/eng/Versions.props b/eng/Versions.props
index 39cfa937609..a03c3acca25 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -27,6 +27,7 @@
2.0.0
2.0.2
2.0.2
+ 2.0.2
2.0.2
1.1.118
0.12.0
diff --git a/src/Microsoft.Data.Sqlite.Core/Extensions/SQLitePCLExtensions.cs b/src/Microsoft.Data.Sqlite.Core/Extensions/SQLitePCLExtensions.cs
index 4fde8afcd64..c823566cf5f 100644
--- a/src/Microsoft.Data.Sqlite.Core/Extensions/SQLitePCLExtensions.cs
+++ b/src/Microsoft.Data.Sqlite.Core/Extensions/SQLitePCLExtensions.cs
@@ -1,13 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System.Collections.Generic;
+
// ReSharper disable once CheckNamespace
// ReSharper disable InconsistentNaming
namespace SQLitePCL
{
internal static class SQLitePCLExtensions
{
- public static bool EncryptionNotSupported()
- => raw.GetNativeLibraryName() == "e_sqlite3";
+ private static readonly Dictionary _knownLibraries = new Dictionary
+ {
+ { "e_sqlcipher", true },
+ { "e_sqlite3", false},
+ { "sqlcipher", true },
+ { "winsqlite3", false }
+ };
+
+ public static bool? EncryptionSupported()
+ => _knownLibraries.TryGetValue(raw.GetNativeLibraryName(), out var supported)
+ ? supported
+ : default(bool?);
}
}
diff --git a/src/Microsoft.Data.Sqlite.Core/Properties/InternalsVisibleTo.cs b/src/Microsoft.Data.Sqlite.Core/Properties/InternalsVisibleTo.cs
index 623cd1c76f2..da0899d9556 100644
--- a/src/Microsoft.Data.Sqlite.Core/Properties/InternalsVisibleTo.cs
+++ b/src/Microsoft.Data.Sqlite.Core/Properties/InternalsVisibleTo.cs
@@ -3,5 +3,9 @@
using System.Runtime.CompilerServices;
+[assembly: InternalsVisibleTo(
+ "Microsoft.Data.Sqlite.e_sqlcipher.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo(
"Microsoft.Data.Sqlite.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
+[assembly: InternalsVisibleTo(
+ "Microsoft.Data.Sqlite.winsqlite3.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
diff --git a/src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs b/src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs
index d3e8ec0d28d..206dfe218bb 100644
--- a/src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs
+++ b/src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs
@@ -245,7 +245,7 @@ public override void Open()
{
if (!string.IsNullOrEmpty(ConnectionOptions.Password))
{
- if (SQLitePCLExtensions.EncryptionNotSupported())
+ if (SQLitePCLExtensions.EncryptionSupported() == false)
{
throw new InvalidOperationException(Resources.EncryptionNotSupported);
}
@@ -256,7 +256,10 @@ public override void Open()
"SELECT quote($password);",
new SqliteParameter("$password", ConnectionOptions.Password));
this.ExecuteNonQuery("PRAGMA key = " + quotedPassword + ";");
+ }
+ if (SQLitePCLExtensions.EncryptionSupported() != false)
+ {
// NB: Forces decryption. Throws when the key is incorrect.
this.ExecuteNonQuery("SELECT COUNT(*) FROM sqlite_master;");
}
diff --git a/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.Tests.csproj b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.Tests.csproj
index f774e88af44..b1d2594a916 100644
--- a/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.Tests.csproj
+++ b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.Tests.csproj
@@ -2,6 +2,7 @@
$(DefaultNetCoreTargetFramework)
+ $(DefineConstants);E_SQLITE3
diff --git a/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.e_sqlcipher.Tests.csproj b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.e_sqlcipher.Tests.csproj
new file mode 100644
index 00000000000..1d4bf4b7a03
--- /dev/null
+++ b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.e_sqlcipher.Tests.csproj
@@ -0,0 +1,16 @@
+
+
+
+ $(DefaultNetCoreTargetFramework)
+ $(DefineConstants);E_SQLCIPHER
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.winsqlite3.Tests.csproj b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.winsqlite3.Tests.csproj
new file mode 100644
index 00000000000..900da98f60d
--- /dev/null
+++ b/test/Microsoft.Data.Sqlite.Tests/Microsoft.Data.Sqlite.winsqlite3.Tests.csproj
@@ -0,0 +1,16 @@
+
+
+
+ $(DefaultNetCoreTargetFramework)
+ $(DefineConstants);WINSQLITE3
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs b/test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs
index 3132cdadf5e..6b52947b996 100644
--- a/test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs
+++ b/test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs
@@ -5,11 +5,11 @@
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
-using System.Globalization;
+using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Threading;
using Microsoft.Data.Sqlite.Properties;
+using Microsoft.Data.Sqlite.Utilities;
using Xunit;
using static SQLitePCL.raw;
@@ -260,20 +260,18 @@ public void Open_works_when_memory_shared()
[Fact]
public void Open_works_when_password()
{
- switch (GetNativeLibraryName())
- {
- case "e_sqlite3":
- Open_works_when_password_e_sqlite3();
- break;
-
- // NB: Change project dependencies to test this
- case "e_sqlcipher":
- Open_works_when_password_sqlcipher();
- break;
- }
+#if E_SQLITE3 || WINSQLITE3
+ Open_works_when_password_unsupported();
+#elif E_SQLCIPHER || SQLCIPHER
+ Open_works_when_password_supported();
+#elif SQLITE3
+ Open_works_when_password_might_be_supported();
+#else
+#error Unexpected native library
+#endif
}
- private void Open_works_when_password_e_sqlite3()
+ private void Open_works_when_password_unsupported()
{
using (var connection = new SqliteConnection("Data Source=encrypted.db;Password=password"))
{
@@ -288,12 +286,8 @@ private void Open_works_when_password_e_sqlite3()
}
}
- private void Open_works_when_password_sqlcipher()
+ private void Open_works_when_password_supported()
{
- var es = new CultureInfo("es");
- Thread.CurrentThread.CurrentCulture = es;
- Thread.CurrentThread.CurrentUICulture = es;
-
using (var connection1 = new SqliteConnection("Data Source=encrypted.db;Password=password"))
{
connection1.Open();
@@ -315,6 +309,12 @@ private void Open_works_when_password_sqlcipher()
}
}
+ private void Open_works_when_password_might_be_supported()
+ {
+ using var connection = new SqliteConnection("Data Source=encrypted.db;Password=password");
+ connection.Open();
+ }
+
[Theory]
[InlineData("True", 1L)]
[InlineData("False", 0L)]
diff --git a/test/Microsoft.Data.Sqlite.Tests/TestUtilities/SqliteTestFramework.cs b/test/Microsoft.Data.Sqlite.Tests/TestUtilities/SqliteTestFramework.cs
new file mode 100644
index 00000000000..e475625eb10
--- /dev/null
+++ b/test/Microsoft.Data.Sqlite.Tests/TestUtilities/SqliteTestFramework.cs
@@ -0,0 +1,119 @@
+using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+using System;
+
+#if WINSQLITE3
+using System.Runtime.InteropServices;
+#endif
+
+[assembly: TestFramework(
+ "Microsoft.Data.Sqlite.Tests.TestUtilities.SqliteTestFramework",
+#if E_SQLITE3
+ "Microsoft.Data.Sqlite.Tests")]
+#elif E_SQLCIPHER
+ "Microsoft.Data.Sqlite.e_sqlcipher.Tests")]
+#elif WINSQLITE3
+ "Microsoft.Data.Sqlite.winsqlite3.Tests")]
+#else
+#error Unexpected native library
+#endif
+
+namespace Microsoft.Data.Sqlite.Tests.TestUtilities
+{
+ class SqliteTestFramework : XunitTestFramework
+ {
+ protected SqliteTestFramework(IMessageSink diagnosticMessageSink)
+ : base(diagnosticMessageSink)
+ {
+ }
+
+ protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
+ => new SqliteTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
+ }
+
+ class SqliteTestFrameworkExecutor : XunitTestFrameworkExecutor
+ {
+ public SqliteTestFrameworkExecutor(
+ AssemblyName assemblyName,
+ ISourceInformationProvider sourceInformationProvider,
+ IMessageSink diagnosticMessageSink)
+ : base(assemblyName, sourceInformationProvider, diagnosticMessageSink)
+ {
+ }
+
+ protected override async void RunTestCases(
+ IEnumerable testCases,
+ IMessageSink executionMessageSink,
+ ITestFrameworkExecutionOptions executionOptions)
+ {
+ using var assemblyRunner = new SqliteTestAssemblyRunner(
+ TestAssembly,
+ testCases,
+ DiagnosticMessageSink,
+ executionMessageSink,
+ executionOptions);
+ await assemblyRunner.RunAsync();
+ }
+ }
+
+ class SqliteTestAssemblyRunner : XunitTestAssemblyRunner
+ {
+ public SqliteTestAssemblyRunner(
+ ITestAssembly testAssembly,
+ IEnumerable testCases,
+ IMessageSink diagnosticMessageSink,
+ IMessageSink executionMessageSink,
+ ITestFrameworkExecutionOptions executionOptions)
+ : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions)
+ {
+ }
+
+
+ protected override Task RunTestCollectionAsync(
+ IMessageBus messageBus,
+ ITestCollection testCollection,
+ IEnumerable testCases,
+ CancellationTokenSource cancellationTokenSource)
+ {
+#if WINSQLITE3
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return SkipAll("winsqlite3 isn't supported on " + RuntimeInformation.OSDescription);
+ }
+
+#endif
+ var version = new SqliteConnection().ServerVersion;
+ if (new Version(version) < new Version(3, 16, 0))
+ {
+ return SkipAll("SQLite " + version + " isn't supported. Upgrade to 3.16.0 or higher");
+ }
+
+ return new XunitTestCollectionRunner(
+ testCollection,
+ testCases,
+ DiagnosticMessageSink,
+ messageBus,
+ TestCaseOrderer,
+ new ExceptionAggregator(Aggregator),
+ cancellationTokenSource)
+ .RunAsync();
+
+ Task SkipAll(string reason)
+ {
+ var count = 0;
+ foreach (var testCase in testCases)
+ {
+ messageBus.QueueMessage(new TestSkipped(new XunitTest(testCase, testCase.DisplayName), reason));
+ count++;
+ }
+
+ return Task.FromResult(new RunSummary { Skipped = count, Total = count });
+ }
+ }
+ }
+}