From a6d179d401089e45eb93ed3ae12a24da075b1163 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Mon, 25 Dec 2023 22:32:55 -0500 Subject: [PATCH] Switch to namespace from module for Sqlite - Complete C# test migration --- src/Sqlite/Library.fs | 41 +- src/Tests.CSharp/SqliteCSharpTests.cs | 1184 +++++++++++++------------ src/Tests.CSharp/SqliteDb.cs | 2 +- src/Tests/Program.fs | 2 +- 4 files changed, 658 insertions(+), 571 deletions(-) diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index 25dedcd..abee0aa 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -1,5 +1,4 @@ -/// Document store implementation for SQLite -module BitBadger.Documents.Sqlite +namespace BitBadger.Documents.Sqlite open BitBadger.Documents open Microsoft.Data.Sqlite @@ -106,11 +105,14 @@ module Results = ToCustomList<'TDoc>(cmd, fromData<'TDoc>) -/// Execute a non-query command -let internal write (cmd: SqliteCommand) = backgroundTask { - let! _ = cmd.ExecuteNonQueryAsync() - () -} +[] +module internal Helpers = + + /// Execute a non-query command + let internal write (cmd: SqliteCommand) = backgroundTask { + let! _ = cmd.ExecuteNonQueryAsync() + () + } /// Versions of queries that accept a SqliteConnection as the last parameter @@ -373,17 +375,21 @@ module Definition = use conn = Configuration.dbConn () WithConn.Definition.ensureTable name conn -/// Insert a new document -[] -let insert<'TDoc> tableName (document: 'TDoc) = - use conn = Configuration.dbConn () - WithConn.insert tableName document conn +/// Document insert/save functions +[] +module Document = + + /// Insert a new document + [] + let insert<'TDoc> tableName (document: 'TDoc) = + use conn = Configuration.dbConn () + WithConn.insert tableName document conn -/// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert") -[] -let save<'TDoc> tableName (document: 'TDoc) = - use conn = Configuration.dbConn () - WithConn.save tableName document conn + /// Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert") + [] + let save<'TDoc> tableName (document: 'TDoc) = + use conn = Configuration.dbConn () + WithConn.save tableName document conn /// Commands to count documents [] @@ -613,6 +619,7 @@ module Extensions = open System.Runtime.CompilerServices /// C# extensions on the SqliteConnection type +[] type SqliteConnectionCSharpExtensions = /// Execute a query that returns a list of results diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index c0f9873..73baea0 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -2,17 +2,51 @@ using Expecto; using Microsoft.Data.Sqlite; using Microsoft.FSharp.Core; -using Docs = BitBadger.Documents; +using BitBadger.Documents.Sqlite; namespace BitBadger.Documents.Tests.CSharp; -using static Sqlite; +using static Runner; /// /// C# tests for the SQLite implementation of BitBadger.Documents /// public static class SqliteCSharpTests { + /// + /// Unit tests for the SQLite library + /// + public static Test Unit = + TestList("Unit", new[] + { + TestList("Parameters", new[] + { + TestCase("Id succeeds", () => + { + var theParam = Parameters.Id(7); + Expect.equal(theParam.ParameterName, "@id", "The parameter name is incorrect"); + Expect.equal(theParam.Value, "7", "The parameter value is incorrect"); + }), + TestCase("Json succeeds", () => + { + var theParam = Parameters.Json("@test", new { Nice = "job" }); + Expect.equal(theParam.ParameterName, "@test", "The parameter name is incorrect"); + Expect.equal(theParam.Value, "{\"Nice\":\"job\"}", "The parameter value is incorrect"); + }), + TestCase("Field succeeds", () => + { + var theParam = Parameters.Field(99); + Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect"); + Expect.equal(theParam.Value, 99, "The parameter value is incorrect"); + }), + TestCase("None succeeds", () => + { + Expect.isEmpty(Parameters.None, "The parameter list should have been empty"); + }) + }) + // Results are exhaustively executed in the context of other tests + }); + private static readonly List TestDocuments = new() { new() { Id = "one", Value = "FIRST!", NumValue = 0 }, @@ -24,32 +58,32 @@ public static class SqliteCSharpTests private static async Task LoadDocs() { - foreach (var doc in TestDocuments) await Insert(SqliteDb.TableName, doc); + foreach (var doc in TestDocuments) await Document.Insert(SqliteDb.TableName, doc); } [Tests] public static Test Integration = - Runner.TestList("Sqlite.C# Integration", new[] + TestList("Integration", new[] { - Runner.TestCase("Configuration.UseConnectionString succeeds", () => + TestCase("Configuration.UseConnectionString succeeds", () => { try { - Configuration.UseConnectionString("Data Source=test.db"); - Expect.equal(Configuration.connectionString, + Sqlite.Configuration.UseConnectionString("Data Source=test.db"); + Expect.equal(Sqlite.Configuration.connectionString, new FSharpOption("Data Source=test.db;Foreign Keys=True"), "Connection string incorrect"); } finally { - Configuration.UseConnectionString("Data Source=:memory:"); + Sqlite.Configuration.UseConnectionString("Data Source=:memory:"); } }), - Runner.TestList("Custom", new[] + TestList("Custom", new[] { - Runner.TestList("Single", new [] + TestList("Single", new [] { - Runner.TestCase("succeeds when a row is found", async () => + TestCase("succeeds when a row is found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -57,10 +91,10 @@ public static class SqliteCSharpTests var doc = await Custom.Single( $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id", new[] { Parameters.Id("one") }, Results.FromData); - if (doc is null) Expect.isTrue(false, "There should have been a document returned"); + Expect.isNotNull(doc, "There should have been a document returned"); Expect.equal(doc!.Id, "one", "The incorrect document was returned"); }), - Runner.TestCase("succeeds when a row is not found", async () => + TestCase("succeeds when a row is not found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -71,18 +105,18 @@ public static class SqliteCSharpTests Expect.isNull(doc, "There should not have been a document returned"); }) }), - Runner.TestList("List", new[] + TestList("List", new[] { - Runner.TestCase("succeeds when data is found", async () => + TestCase("succeeds when data is found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); - var docs = await Custom.List(Docs.Query.SelectFromTable(SqliteDb.TableName), Parameters.None, + var docs = await Custom.List(Query.SelectFromTable(SqliteDb.TableName), Parameters.None, Results.FromData); Expect.equal(docs.Count, 5, "There should have been 5 documents returned"); }), - Runner.TestCase("succeeds when data is not found", async () => + TestCase("succeeds when data is not found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -93,9 +127,9 @@ public static class SqliteCSharpTests Expect.isEmpty(docs, "There should have been no documents returned"); }) }), - Runner.TestList("NonQuery", new[] + TestList("NonQuery", new[] { - Runner.TestCase("succeeds when operating on data", async () => + TestCase("succeeds when operating on data", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -105,7 +139,7 @@ public static class SqliteCSharpTests var remaining = await Count.All(SqliteDb.TableName); Expect.equal(remaining, 0L, "There should be no documents remaining in the table"); }), - Runner.TestCase("succeeds when no data matches where clause", async () => + TestCase("succeeds when no data matches where clause", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -118,7 +152,7 @@ public static class SqliteCSharpTests Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table"); }) }), - Runner.TestCase("Scalar succeeds", async () => + TestCase("Scalar succeeds", async () => { await using var db = await SqliteDb.BuildDb(); @@ -126,9 +160,9 @@ public static class SqliteCSharpTests Expect.equal(nbr, 5, "The query should have returned the number 5"); }) }), - Runner.TestList("Definition", new[] + TestList("Definition", new[] { - Runner.TestCase("EnsureTable succeeds", async () => + TestCase("EnsureTable succeeds", async () => { await using var db = await SqliteDb.BuildDb(); @@ -155,25 +189,25 @@ public static class SqliteCSharpTests } }) }), - Runner.TestList("Insert", new[] + TestList("Document.Insert", new[] { - Runner.TestCase("succeeds", async () => + TestCase("succeeds", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should be no documents in the table"); - await Insert(SqliteDb.TableName, + Expect.isEmpty(before, "There should be no documents in the table"); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } }); var after = await Find.All(SqliteDb.TableName); Expect.equal(after.Count, 1, "There should have been one document inserted"); }), - Runner.TestCase("fails for duplicate key", async () => + TestCase("fails for duplicate key", async () => { await using var db = await SqliteDb.BuildDb(); - await Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); try { - await Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); Expect.isTrue(false, "An exception should have been raised for duplicate document ID insert"); } catch (Exception) @@ -182,42 +216,42 @@ public static class SqliteCSharpTests } }) }), - Runner.TestList("Save", new[] + TestList("Document.Save", new[] { - Runner.TestCase("succeeds when a document is inserted", async () => + TestCase("succeeds when a document is inserted", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should be no documents in the table"); + Expect.isEmpty(before, "There should be no documents in the table"); - await Save(SqliteDb.TableName, + await Document.Save(SqliteDb.TableName, new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } }); var after = await Find.All(SqliteDb.TableName); Expect.equal(after.Count, 1, "There should have been one document inserted"); }), - Runner.TestCase("succeeds when a document is updated", async () => + TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); - await Insert(SqliteDb.TableName, + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } }); var before = await Find.ById(SqliteDb.TableName, "test"); - if (before is null) Expect.isTrue(false, "There should have been a document returned"); + Expect.isNotNull(before, "There should have been a document returned"); Expect.equal(before!.Id, "test", "The document is not correct"); Expect.isNotNull(before.Sub, "There should have been a sub-document"); Expect.equal(before.Sub!.Foo, "a", "The document is not correct"); Expect.equal(before.Sub.Bar, "b", "The document is not correct"); - await Save(SqliteDb.TableName, new JsonDocument { Id = "test" }); + await Document.Save(SqliteDb.TableName, new JsonDocument { Id = "test" }); var after = await Find.ById(SqliteDb.TableName, "test"); - if (after is null) Expect.isTrue(false, "There should have been a document returned post-update"); + Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(after!.Id, "test", "The updated document is not correct"); Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document"); }) }), - Runner.TestList("Count", new[] + TestList("Count", new[] { - Runner.TestCase("All succeeds", async () => + TestCase("All succeeds", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -225,7 +259,7 @@ public static class SqliteCSharpTests var theCount = await Count.All(SqliteDb.TableName); Expect.equal(theCount, 5L, "There should have been 5 matching documents"); }), - Runner.TestCase("ByField succeeds", async () => + TestCase("ByField succeeds", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -234,11 +268,11 @@ public static class SqliteCSharpTests Expect.equal(theCount, 2L, "There should have been 2 matching documents"); }) }), - Runner.TestList("Exists", new[] + TestList("Exists", new[] { - Runner.TestList("ById", new[] + TestList("ById", new[] { - Runner.TestCase("succeeds when a document exists", async () => + TestCase("succeeds when a document exists", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -246,7 +280,7 @@ public static class SqliteCSharpTests var exists = await Exists.ById(SqliteDb.TableName, "three"); Expect.isTrue(exists, "There should have been an existing document"); }), - Runner.TestCase("succeeds when a document does not exist", async () => + TestCase("succeeds when a document does not exist", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -255,9 +289,9 @@ public static class SqliteCSharpTests Expect.isFalse(exists, "There should not have been an existing document"); }) }), - Runner.TestList("ByField", new[] + TestList("ByField", new[] { - Runner.TestCase("succeeds when documents exist", async () => + TestCase("succeeds when documents exist", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -265,7 +299,7 @@ public static class SqliteCSharpTests var exists = await Exists.ByField(SqliteDb.TableName, "NumValue", Op.GE, 10); Expect.isTrue(exists, "There should have been existing documents"); }), - Runner.TestCase("succeeds when no matching documents exist", async () => + TestCase("succeeds when no matching documents exist", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -275,40 +309,40 @@ public static class SqliteCSharpTests }) }) }), - Runner.TestList("Find", new[] + TestList("Find", new[] { - Runner.TestList("All", new[] + TestList("All", new[] { - Runner.TestCase("succeeds when there is data", async () => + TestCase("succeeds when there is data", async () => { await using var db = await SqliteDb.BuildDb(); - await Insert(SqliteDb.TableName, new JsonDocument { Id = "one", Value = "two" }); - await Insert(SqliteDb.TableName, new JsonDocument { Id = "three", Value = "four" }); - await Insert(SqliteDb.TableName, new JsonDocument { Id = "five", Value = "six" }); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "one", Value = "two" }); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "three", Value = "four" }); + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "five", Value = "six" }); var results = await Find.All(SqliteDb.TableName); Expect.equal(results.Count, 3, "There should have been 3 documents returned"); }), - Runner.TestCase("succeeds when there is no data", async () => + TestCase("succeeds when there is no data", async () => { await using var db = await SqliteDb.BuildDb(); var results = await Find.All(SqliteDb.TableName); - Expect.equal(results.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(results, "There should have been no documents returned"); }) }), - Runner.TestList("ById", new[] + TestList("ById", new[] { - Runner.TestCase("succeeds when a document is found", async () => + TestCase("succeeds when a document is found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); var doc = await Find.ById(SqliteDb.TableName, "two"); - if (doc is null) Expect.isTrue(false, "There should have been a document returned"); + Expect.isNotNull(doc, "There should have been a document returned"); Expect.equal(doc!.Id, "two", "The incorrect document was returned"); }), - Runner.TestCase("succeeds when a document is not found", async () => + TestCase("succeeds when a document is not found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -317,9 +351,9 @@ public static class SqliteCSharpTests Expect.isNull(doc, "There should not have been a document returned"); }) }), - Runner.TestList("ByField", new[] + TestList("ByField", new[] { - Runner.TestCase("succeeds when documents are found", async () => + TestCase("succeeds when documents are found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -327,36 +361,36 @@ public static class SqliteCSharpTests var docs = await Find.ByField(SqliteDb.TableName, "NumValue", Op.GT, 15); Expect.equal(docs.Count, 2, "There should have been two documents returned"); }), - Runner.TestCase("succeeds when documents are not found", async () => + TestCase("succeeds when documents are not found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); var docs = await Find.ByField(SqliteDb.TableName, "Value", Op.EQ, "mauve"); - Expect.equal(docs.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(docs, "There should have been no documents returned"); }) }), - Runner.TestList("FirstByField", new[] + TestList("FirstByField", new[] { - Runner.TestCase("succeeds when a document is found", async () => + TestCase("succeeds when a document is found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); var doc = await Find.FirstByField(SqliteDb.TableName, "Value", Op.EQ, "another"); - if (doc is null) Expect.isTrue(false, "There should have been a document returned"); + Expect.isNotNull(doc, "There should have been a document returned"); Expect.equal(doc!.Id, "two", "The incorrect document was returned"); }), - Runner.TestCase("succeeds when multiple documents are found", async () => + TestCase("succeeds when multiple documents are found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); var doc = await Find.FirstByField(SqliteDb.TableName, "Sub.Foo", Op.EQ, "green"); - if (doc is null) Expect.isTrue(false, "There should have been a document returned"); + Expect.isNotNull(doc, "There should have been a document returned"); Expect.contains(new[] { "two", "four" }, doc!.Id, "An incorrect document was returned"); }), - Runner.TestCase("succeeds when a document is not found", async () => + TestCase("succeeds when a document is not found", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -366,11 +400,11 @@ public static class SqliteCSharpTests }) }) }), - Runner.TestList("Update", new[] + TestList("Update", new[] { - Runner.TestList("Full", new[] + TestList("Full", new[] { - Runner.TestCase("succeeds when a document is updated", async () => + TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -378,28 +412,27 @@ public static class SqliteCSharpTests var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } }; await Update.Full(SqliteDb.TableName, "one", testDoc); var after = await Find.ById(SqliteDb.TableName, "one"); - if (after is null) - Expect.isTrue(false, "There should have been a document returned post-update"); + Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(after!.Id, "one", "The updated document is not correct"); Expect.isNotNull(after.Sub, "The updated document should have had a sub-document"); Expect.equal(after.Sub!.Foo, "blue", "The updated sub-document is not correct"); Expect.equal(after.Sub.Bar, "red", "The updated sub-document is not correct"); }), - Runner.TestCase("succeeds when no document is updated", async () => + TestCase("succeeds when no document is updated", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(before, "There should have been no documents returned"); // This not raising an exception is the test await Update.Full(SqliteDb.TableName, "test", new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); }) }), - Runner.TestList("FullFunc", new[] + TestList("FullFunc", new[] { - Runner.TestCase("succeeds when a document is updated", async () => + TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -407,53 +440,51 @@ public static class SqliteCSharpTests await Update.FullFunc(SqliteDb.TableName, doc => doc.Id, new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); var after = await Find.ById(SqliteDb.TableName, "one"); - if (after is null) - Expect.isTrue(false, "There should have been a document returned post-update"); + Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(after!.Id, "one", "The updated document is incorrect"); Expect.equal(after.Value, "le un", "The updated document is incorrect"); Expect.equal(after.NumValue, 1, "The updated document is incorrect"); Expect.isNull(after.Sub, "The updated document should not have a sub-document"); }), - Runner.TestCase("succeeds when no document is updated", async () => + TestCase("succeeds when no document is updated", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(before, "There should have been no documents returned"); // This not raising an exception is the test await Update.FullFunc(SqliteDb.TableName, doc => doc.Id, new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); }) }), - Runner.TestList("PartialById", new[] + TestList("PartialById", new[] { - Runner.TestCase("succeeds when a document is updated", async () => + TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); await Update.PartialById(SqliteDb.TableName, "one", new { NumValue = 44 }); var after = await Find.ById(SqliteDb.TableName, "one"); - if (after is null) - Expect.isTrue(false, "There should have been a document returned post-update"); + Expect.isNotNull(after, "There should have been a document returned post-update"); Expect.equal(after!.Id, "one", "The updated document is not correct"); Expect.equal(after.NumValue, 44, "The updated document is not correct"); }), - Runner.TestCase("succeeds when no document is updated", async () => + TestCase("succeeds when no document is updated", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(before, "There should have been no documents returned"); // This not raising an exception is the test await Update.PartialById(SqliteDb.TableName, "test", new { Foo = "green" }); }) }), - Runner.TestList("PartialByField", new[] + TestList("PartialByField", new[] { - Runner.TestCase("succeeds when a document is updated", async () => + TestCase("succeeds when a document is updated", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -463,12 +494,12 @@ public static class SqliteCSharpTests var after = await Count.ByField(SqliteDb.TableName, "NumValue", Op.EQ, 77); Expect.equal(after, 2L, "There should have been 2 documents returned"); }), - Runner.TestCase("succeeds when no document is updated", async () => + TestCase("succeeds when no document is updated", async () => { await using var db = await SqliteDb.BuildDb(); var before = await Find.All(SqliteDb.TableName); - Expect.equal(before.Count, 0, "There should have been no documents returned"); + Expect.isEmpty(before, "There should have been no documents returned"); // This not raising an exception is the test await Update.PartialByField(SqliteDb.TableName, "Value", Op.EQ, "burgundy", @@ -476,11 +507,11 @@ public static class SqliteCSharpTests }) }) }), - Runner.TestList("Delete", new[] + TestList("Delete", new[] { - Runner.TestList("ById", new[] + TestList("ById", new[] { - Runner.TestCase("succeeds when a document is deleted", async () => + TestCase("succeeds when a document is deleted", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -489,7 +520,7 @@ public static class SqliteCSharpTests var remaining = await Count.All(SqliteDb.TableName); Expect.equal(remaining, 4L, "There should have been 4 documents remaining"); }), - Runner.TestCase("succeeds when a document is not deleted", async () => + TestCase("succeeds when a document is not deleted", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -499,9 +530,9 @@ public static class SqliteCSharpTests Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); }) }), - Runner.TestList("ByField", new[] + TestList("ByField", new[] { - Runner.TestCase("succeeds when documents are deleted", async () => + TestCase("succeeds when documents are deleted", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -510,7 +541,7 @@ public static class SqliteCSharpTests var remaining = await Count.All(SqliteDb.TableName); Expect.equal(remaining, 2L, "There should have been 2 documents remaining"); }), - Runner.TestCase("succeeds when documents are not deleted", async () => + TestCase("succeeds when documents are not deleted", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); @@ -521,456 +552,505 @@ public static class SqliteCSharpTests }) }) }), - // Runner.TestList("Extensions" [ - // Runner.TestCase("EnsureTable succeeds" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let itExists (name: string) = task { - // let! result = - // conn.CustomScalar( - // $"SELECT EXISTS (SELECT 1 FROM {Db.catalog} WHERE name = @name) AS it", - // [ SqliteParameter("@name", name) ], - // System.Func _.GetInt64(0)) - // return result > 0L - // } - // - // let! exists = itExists "ensured" - // let! alsoExists = itExists "idx_ensured_key" - // Expect.isFalse exists "The table should not exist already" - // Expect.isFalse alsoExists "The key index should not exist already" - // - // await Definition.EnsureTable "ensured" - // let! exists' = itExists "ensured" - // let! alsoExists' = itExists "idx_ensured_key" - // Expect.isTrue exists' "The table should now exist" - // Expect.isTrue alsoExists' "The key index should now exist" - // } - // Runner.TestList("Insert" [ - // Runner.TestCase("succeeds" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should be no documents in the table" - // await conn.Insert( - // SqliteDb.TableName , - // JsonDocument(Id = "turkey", Sub = Some (SubDocument(Foo = "gobble", Bar = "gobble")))) - // let! after = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf after 1u isTrue "There should have been one document inserted" - // } - // Runner.TestCase("fails for duplicate key" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await conn.Insert(SqliteDb.TableName , JsonDocument(Id = "test")) - // Expect.throws - // (fun () -> - // conn.Insert(SqliteDb.TableName , JsonDocument(Id = "test")) - // |> Async.AwaitTask - // |> Async.RunSynchronously) - // "An exception should have been raised for duplicate document ID insert" - // } - // ] - // Runner.TestList("Save" [ - // Runner.TestCase("succeeds when a document is inserted" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should be no documents in the table" - // - // await conn.Save( - // SqliteDb.TableName , - // JsonDocument(Id = "test", Sub = Some (SubDocument(Foo = "a", Bar = "b")))) - // let! after = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf after 1u isTrue "There should have been one document inserted" - // } - // Runner.TestCase("succeeds when a document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await conn.Insert( - // SqliteDb.TableName , - // JsonDocument(Id = "test", Sub = Some (SubDocument(Foo = "a", Bar = "b")))) - // - // let! before = conn.FindById(SqliteDb.TableName , "test") - // if isNull before then Expect.isTrue false "There should have been a document returned" - // let before = before :> JsonDocument - // Expect.equal before.Id "test" "The document is not correct" - // Expect.isSome before.Sub "There should have been a sub-document" - // Expect.equal before.Sub.Value.Foo "a" "The document is not correct" - // Expect.equal before.Sub.Value.Bar "b" "The document is not correct" - // - // await Save(SqliteDb.TableName , JsonDocument(Id = "test")) - // let! after = conn.FindById(SqliteDb.TableName , "test") - // if isNull after then Expect.isTrue false "There should have been a document returned post-update" - // let after = after :> JsonDocument - // Expect.equal after.Id "test" "The updated document is not correct" - // Expect.isNone after.Sub "There should not have been a sub-document in the updated document" - // } - // ] - // Runner.TestCase("CountAll succeeds" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! theCount = conn.CountAll SqliteDb.TableName - // Expect.equal theCount 5L "There should have been 5 matching documents" - // } - // Runner.TestCase("CountByField succeeds" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! theCount = conn.CountByField(SqliteDb.TableName , "Value", Op.EQ, "purple") - // Expect.equal theCount 2L "There should have been 2 matching documents" - // } - // Runner.TestList("ExistsById" [ - // Runner.TestCase("succeeds when a document exists" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! exists = conn.ExistsById(SqliteDb.TableName , "three") - // Expect.isTrue exists "There should have been an existing document" - // } - // Runner.TestCase("succeeds when a document does not exist" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! exists = conn.ExistsById(SqliteDb.TableName , "seven") - // Expect.isFalse exists "There should not have been an existing document" - // } - // ] - // Runner.TestList("ExistsByField" [ - // Runner.TestCase("succeeds when documents exist" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! exists = conn.ExistsByField(SqliteDb.TableName , "NumValue", Op.GE, 10) - // Expect.isTrue exists "There should have been existing documents" - // } - // Runner.TestCase("succeeds when no matching documents exist" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! exists = conn.ExistsByField(SqliteDb.TableName , "Nothing", Op.EQ, "none") - // Expect.isFalse exists "There should not have been any existing documents" - // } - // ] - // Runner.TestList("FindAll" [ - // Runner.TestCase("succeeds when there is data" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // - // await conn.Insert(SqliteDb.TableName , JsonDocument(Id = "one", Value = "two")) - // await conn.Insert(SqliteDb.TableName , JsonDocument(Id = "three", Value = "four")) - // await conn.Insert(SqliteDb.TableName , JsonDocument(Id = "five", Value = "six")) - // - // let! results = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf results 3u isTrue "There should have been 3 documents returned" - // } - // Runner.TestCase("succeeds when there is no data" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! results = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf results 0u isTrue "There should have been no documents returned" - // } - // ] - // Runner.TestList("FindById" [ - // Runner.TestCase("succeeds when a document is found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = conn.FindById(SqliteDb.TableName , "two") - // if isNull doc then Expect.isTrue false "There should have been a document returned" - // Expect.equal (doc :> JsonDocument).Id "two" "The incorrect document was returned" - // } - // Runner.TestCase("succeeds when a document is not found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = conn.FindById(SqliteDb.TableName , "three hundred eighty-seven") - // Expect.isNull doc "There should not have been a document returned" - // } - // ] - // Runner.TestList("FindByField" [ - // Runner.TestCase("succeeds when documents are found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! docs = conn.FindByField(SqliteDb.TableName , "NumValue", Op.GT, 15) - // Expect.hasCountOf docs 2u isTrue "There should have been two documents returned" - // } - // Runner.TestCase("succeeds when documents are not found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! docs = conn.FindByField(SqliteDb.TableName , "Value", Op.EQ, "mauve") - // Expect.hasCountOf docs 0u isTrue "There should have been no documents returned" - // } - // ] - // Runner.TestList("FindFirstByField" [ - // Runner.TestCase("succeeds when a document is found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = conn.FindFirstByField(SqliteDb.TableName , "Value", Op.EQ, "another") - // if isNull doc then Expect.isTrue false "There should have been a document returned" - // Expect.equal (doc :> JsonDocument).Id "two" "The incorrect document was returned" - // } - // Runner.TestCase("succeeds when multiple documents are found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = conn.FindFirstByField(SqliteDb.TableName , "Sub.Foo", Op.EQ, "green") - // if isNull doc then Expect.isTrue false "There should have been a document returned" - // Expect.contains [ "two"; "four" ] (doc :> JsonDocument).Id "An incorrect document was returned" - // } - // Runner.TestCase("succeeds when a document is not found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = conn.FindFirstByField(SqliteDb.TableName , "Value", Op.EQ, "absent") - // Expect.isNull doc "There should not have been a document returned" - // } - // ] - // Runner.TestList("UpdateFull" [ - // Runner.TestCase("succeeds when a document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let testDoc = JsonDocument(Id = "one", Sub = Some (SubDocument(Foo = "blue", Bar = "red"))) - // await conn.UpdateFull(SqliteDb.TableName , "one", testDoc) - // let! after = conn.FindById(SqliteDb.TableName , "one") - // if isNull after then Expect.isTrue false "There should have been a document returned post-update" - // let after = after :> JsonDocument - // Expect.equal after.Id "one" "The updated document is not correct" - // Expect.isSome after.Sub "The updated document should have had a sub-document" - // Expect.equal after.Sub.Value.Foo "blue" "The updated sub-document is not correct" - // Expect.equal after.Sub.Value.Bar "red" "The updated sub-document is not correct" - // } - // Runner.TestCase("succeeds when no document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should have been no documents returned" - // - // // This not raising an exception is the test - // await conn.UpdateFull( - // SqliteDb.TableName , - // "test", - // JsonDocument(Id = "x", Sub = Some (SubDocument(Foo = "blue", Bar = "red")))) - // } - // ] - // Runner.TestList("UpdateFullFunc" [ - // Runner.TestCase("succeeds when a document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.UpdateFullFunc( - // SqliteDb.TableName , - // System.Func _.Id, - // JsonDocument(Id = "one", Value = "le un", NumValue = 1, Sub = None)) - // let! after = conn.FindById(SqliteDb.TableName , "one") - // if isNull after then Expect.isTrue false "There should have been a document returned post-update" - // let after = after :> JsonDocument - // Expect.equal after.Id "one" "The updated document is incorrect" - // Expect.equal after.Value "le un" "The updated document is incorrect" - // Expect.equal after.NumValue 1 "The updated document is incorrect" - // Expect.isNone after.Sub "The updated document should not have a sub-document" - // } - // Runner.TestCase("succeeds when no document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should have been no documents returned" - // - // // This not raising an exception is the test - // await conn.UpdateFullFunc( - // SqliteDb.TableName , - // System.Func _.Id, - // JsonDocument(Id = "one", Value = "le un", NumValue = 1, Sub = None)) - // } - // ] - // Runner.TestList("UpdatePartialById" [ - // Runner.TestCase("succeeds when a document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.UpdatePartialById(SqliteDb.TableName , "one", {| NumValue = 44 |}) - // let! after = conn.FindById(SqliteDb.TableName , "one") - // if isNull after then Expect.isTrue false "There should have been a document returned post-update" - // let after = after :> JsonDocument - // Expect.equal after.Id "one" "The updated document is not correct" - // Expect.equal after.NumValue 44 "The updated document is not correct" - // } - // Runner.TestCase("succeeds when no document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should have been no documents returned" - // - // // This not raising an exception is the test - // await conn.UpdatePartialById(SqliteDb.TableName , "test", {| Foo = "green" |}) - // } - // ] - // Runner.TestList("UpdatePartialByField" [ - // Runner.TestCase("succeeds when a document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.UpdatePartialByField(SqliteDb.TableName , "Value", Op.EQ, "purple", {| NumValue = 77 |}) - // let! after = conn.CountByField(SqliteDb.TableName , "NumValue", Op.EQ, 77) - // Expect.equal after 2L "There should have been 2 documents returned" - // } - // Runner.TestCase("succeeds when no document is updated" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // let! before = conn.FindAll SqliteDb.TableName - // Expect.hasCountOf before 0u isTrue "There should have been no documents returned" - // - // // This not raising an exception is the test - // await conn.UpdatePartialByField(SqliteDb.TableName , "Value", Op.EQ, "burgundy", {| Foo = "green" |}) - // } - // ] - // Runner.TestList("DeleteById" [ - // Runner.TestCase("succeeds when a document is deleted" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.DeleteById(SqliteDb.TableName , "four") - // let! remaining = conn.CountAll SqliteDb.TableName - // Expect.equal remaining 4L "There should have been 4 documents remaining" - // } - // Runner.TestCase("succeeds when a document is not deleted" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.DeleteById(SqliteDb.TableName , "thirty") - // let! remaining = conn.CountAll SqliteDb.TableName - // Expect.equal remaining 5L "There should have been 5 documents remaining" - // } - // ] - // Runner.TestList("DeleteByField" [ - // Runner.TestCase("succeeds when documents are deleted" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.DeleteByField(SqliteDb.TableName , "Value", Op.NE, "purple") - // let! remaining = conn.CountAll SqliteDb.TableName - // Expect.equal remaining 2L "There should have been 2 documents remaining" - // } - // Runner.TestCase("succeeds when documents are not deleted" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.DeleteByField(SqliteDb.TableName , "Value", Op.EQ, "crimson") - // let! remaining = Count.All SqliteDb.TableName - // Expect.equal remaining 5L "There should have been 5 documents remaining" - // } - // ] - // Runner.TestList("CustomSingle" [ - // Runner.TestCase("succeeds when a row is found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = - // conn.CustomSingle( - // $"SELECT data FROM {SqliteDb.TableName } WHERE data ->> 'Id' = @id", - // [ SqliteParameter("@id", "one") ], - // FromData) - // if isNull doc then Expect.isTrue false "There should have been a document returned" - // Expect.equal (doc :> JsonDocument).Id "one" "The incorrect document was returned" - // } - // Runner.TestCase("succeeds when a row is not found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! doc = - // conn.CustomSingle( - // $"SELECT data FROM {SqliteDb.TableName } WHERE data ->> 'Id' = @id", - // [ SqliteParameter("@id", "eighty") ], - // FromData) - // Expect.isNull doc "There should not have been a document returned" - // } - // ] - // Runner.TestList("CustomList" [ - // Runner.TestCase("succeeds when data is found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! docs = conn.CustomList(Query.SelectFromTable SqliteDb.TableName , [], FromData) - // Expect.hasCountOf docs 5u isTrue "There should have been 5 documents returned" - // } - // Runner.TestCase("succeeds when data is not found" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // let! docs = - // conn.CustomList( - // $"SELECT data FROM {SqliteDb.TableName } WHERE data ->> 'NumValue' > @value", - // [ SqliteParameter("@value", 100) ], - // FromData) - // Expect.isEmpty docs "There should have been no documents returned" - // } - // ] - // Runner.TestList("CustomNonQuery" [ - // Runner.TestCase("succeeds when operating on data" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName }", []) - // - // let! remaining = conn.CountAll SqliteDb.TableName - // Expect.equal remaining 0L "There should be no documents remaining in the table" - // } - // Runner.TestCase("succeeds when no data matches where clause" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // await LoadDocs(); - // - // await conn.CustomNonQuery( - // $"DELETE FROM {SqliteDb.TableName } WHERE data ->> 'NumValue' > @value", - // [ SqliteParameter("@value", 100) ]) - // - // let! remaining = conn.CountAll SqliteDb.TableName - // Expect.equal remaining 5L "There should be 5 documents remaining in the table" - // } - // ] - // Runner.TestCase("CustomScalar succeeds" { - // use! db = Db.buildDb () - // use conn = Configuration.DbConn() - // - // let! nbr = - // conn.CustomScalar("SELECT 5 AS test_value", [], System.Func _.GetInt32(0)) - // Expect.equal nbr 5 "The query should have returned the number 5" - // } - // ] - // test "clean up database" { - // Configuration.UseConnectionString "data source=:memory:" - // } - // } - // ] - // |> testSequenced) + TestList("Extensions", new[] + { + TestList("CustomSingle", new[] + { + TestCase("succeeds when a row is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.CustomSingle( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id", + new[] { Parameters.Id("one") }, Results.FromData); + Expect.isNotNull(doc, "There should have been a document returned"); + Expect.equal(doc!.Id, "one", "The incorrect document was returned"); + }), + TestCase("succeeds when a row is not found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.CustomSingle( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id", + new[] { Parameters.Id("eighty") }, Results.FromData); + Expect.isNull(doc, "There should not have been a document returned"); + }) + }), + TestList("CustomList", new[] + { + TestCase("succeeds when data is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var docs = await conn.CustomList(Query.SelectFromTable(SqliteDb.TableName), Parameters.None, + Results.FromData); + Expect.equal(docs.Count, 5, "There should have been 5 documents returned"); + }), + TestCase("succeeds when data is not found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var docs = await conn.CustomList( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", + new[] { new SqliteParameter("@value", 100) }, Results.FromData); + Expect.isEmpty(docs, "There should have been no documents returned"); + }) + }), + TestList("CustomNonQuery", new[] + { + TestCase("succeeds when operating on data", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.CustomNonQuery($"DELETE FROM {SqliteDb.TableName}", Parameters.None); + + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 0L, "There should be no documents remaining in the table"); + }), + TestCase("succeeds when no data matches where clause", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.CustomNonQuery( + $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", + new[] { new SqliteParameter("@value", 100) }); + + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table"); + }) + }), + TestCase("CustomScalar succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + + var nbr = await conn.CustomScalar("SELECT 5 AS test_value", Parameters.None, + rdr => rdr.GetInt32(0)); + Expect.equal(nbr, 5, "The query should have returned the number 5"); + }), + TestCase("EnsureTable succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + + Func> itExists = async name => + { + var result = await conn.CustomScalar( + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it", + new SqliteParameter[] { new("@name", name) }, + rdr => rdr.GetInt64(0)); + return result > 0L; + }; + + var exists = await itExists("ensured"); + var alsoExists = await itExists("idx_ensured_key"); + Expect.isFalse(exists, "The table should not exist already"); + Expect.isFalse(alsoExists, "The key index should not exist already"); + + await conn.EnsureTable("ensured"); + + exists = await itExists("ensured"); + alsoExists = await itExists("idx_ensured_key"); + Expect.isTrue(exists, "The table should now exist"); + Expect.isTrue(alsoExists, "The key index should now exist"); + }), + TestList("Insert", new[] + { + TestCase("succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should be no documents in the table"); + await conn.Insert(SqliteDb.TableName, + new JsonDocument { Id = "turkey", Sub = new() { Foo = "gobble", Bar = "gobble" } }); + var after = await conn.FindAll(SqliteDb.TableName); + Expect.equal(after.Count, 1, "There should have been one document inserted"); + }), + TestCase("fails for duplicate key", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); + try + { + await Document.Insert(SqliteDb.TableName, new JsonDocument { Id = "test" }); + Expect.isTrue(false, + "An exception should have been raised for duplicate document ID insert"); + } + catch (Exception) + { + // This is what is supposed to happen + } + }) + }), + TestList("Save", new[] + { + TestCase("succeeds when a document is inserted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should be no documents in the table"); + + await conn.Save(SqliteDb.TableName, + new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } }); + var after = await conn.FindAll(SqliteDb.TableName); + Expect.equal(after.Count, 1, "There should have been one document inserted"); + }), + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await conn.Insert(SqliteDb.TableName, + new JsonDocument { Id = "test", Sub = new() { Foo = "a", Bar = "b" } }); + + var before = await conn.FindById(SqliteDb.TableName, "test"); + Expect.isNotNull(before, "There should have been a document returned"); + Expect.equal(before!.Id, "test", "The document is not correct"); + Expect.isNotNull(before.Sub, "There should have been a sub-document"); + Expect.equal(before.Sub!.Foo, "a", "The document is not correct"); + Expect.equal(before.Sub.Bar, "b", "The document is not correct"); + + await conn.Save(SqliteDb.TableName, new JsonDocument { Id = "test" }); + var after = await conn.FindById(SqliteDb.TableName, "test"); + Expect.isNotNull(after, "There should have been a document returned post-update"); + Expect.equal(after!.Id, "test", "The updated document is not correct"); + Expect.isNull(after.Sub, "There should not have been a sub-document in the updated document"); + }) + }), + TestCase("CountAll succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var theCount = await conn.CountAll(SqliteDb.TableName); + Expect.equal(theCount, 5L, "There should have been 5 matching documents"); + }), + TestCase("CountByField succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var theCount = await conn.CountByField(SqliteDb.TableName, "Value", Op.EQ, "purple"); + Expect.equal(theCount, 2L, "There should have been 2 matching documents"); + }), + TestList("ExistsById", new[] + { + TestCase("succeeds when a document exists", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var exists = await conn.ExistsById(SqliteDb.TableName, "three"); + Expect.isTrue(exists, "There should have been an existing document"); + }), + TestCase("succeeds when a document does not exist", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var exists = await conn.ExistsById(SqliteDb.TableName, "seven"); + Expect.isFalse(exists, "There should not have been an existing document"); + }) + }), + TestList("ExistsByField", new[] + { + TestCase("succeeds when documents exist", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var exists = await conn.ExistsByField(SqliteDb.TableName, "NumValue", Op.GE, 10); + Expect.isTrue(exists, "There should have been existing documents"); + }), + TestCase("succeeds when no matching documents exist", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var exists = await conn.ExistsByField(SqliteDb.TableName, "Nothing", Op.EQ, "none"); + Expect.isFalse(exists, "There should not have been any existing documents"); + }) + }), + TestList("FindAll", new[] + { + TestCase("succeeds when there is data", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + + await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "one", Value = "two" }); + await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "three", Value = "four" }); + await conn.Insert(SqliteDb.TableName, new JsonDocument { Id = "five", Value = "six" }); + + var results = await conn.FindAll(SqliteDb.TableName); + Expect.equal(results.Count, 3, "There should have been 3 documents returned"); + }), + TestCase("succeeds when there is no data", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var results = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(results, "There should have been no documents returned"); + }) + }), + TestList("FindById", new[] + { + TestCase("succeeds when a document is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.FindById(SqliteDb.TableName, "two"); + Expect.isNotNull(doc, "There should have been a document returned"); + Expect.equal(doc!.Id, "two", "The incorrect document was returned"); + }), + TestCase("succeeds when a document is not found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.FindById(SqliteDb.TableName, "eighty-seven"); + Expect.isNull(doc, "There should not have been a document returned"); + }) + }), + TestList("FindByField", new[] + { + TestCase("succeeds when documents are found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var docs = await conn.FindByField(SqliteDb.TableName, "NumValue", Op.GT, 15); + Expect.equal(docs.Count, 2, "There should have been two documents returned"); + }), + TestCase("succeeds when documents are not found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var docs = await conn.FindByField(SqliteDb.TableName, "Value", Op.EQ, "mauve"); + Expect.isEmpty(docs, "There should have been no documents returned"); + }) + }), + TestList("FindFirstByField", new[] + { + TestCase("succeeds when a document is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.FindFirstByField(SqliteDb.TableName, "Value", Op.EQ, + "another"); + Expect.isNotNull(doc, "There should have been a document returned"); + Expect.equal(doc!.Id, "two", "The incorrect document was returned"); + }), + TestCase("succeeds when multiple documents are found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.FindFirstByField(SqliteDb.TableName, "Sub.Foo", Op.EQ, + "green"); + Expect.isNotNull(doc, "There should have been a document returned"); + Expect.contains(new[] { "two", "four" }, doc!.Id, "An incorrect document was returned"); + }), + TestCase("succeeds when a document is not found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var doc = await conn.FindFirstByField(SqliteDb.TableName, "Value", Op.EQ, + "absent"); + Expect.isNull(doc, "There should not have been a document returned"); + }) + }), + TestList("UpdateFull", new[] + { + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } }; + await conn.UpdateFull(SqliteDb.TableName, "one", testDoc); + var after = await conn.FindById(SqliteDb.TableName, "one"); + Expect.isNotNull(after, "There should have been a document returned post-update"); + Expect.equal(after.Id, "one", "The updated document is not correct"); + Expect.isNotNull(after.Sub, "The updated document should have had a sub-document"); + Expect.equal(after.Sub!.Foo, "blue", "The updated sub-document is not correct"); + Expect.equal(after.Sub.Bar, "red", "The updated sub-document is not correct"); + }), + TestCase("succeeds when no document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await conn.UpdateFull(SqliteDb.TableName, "test", + new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); + }) + }), + TestList("UpdateFullFunc", new[] + { + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id, + new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); + var after = await conn.FindById(SqliteDb.TableName, "one"); + Expect.isNotNull(after, "There should have been a document returned post-update"); + Expect.equal(after.Id, "one", "The updated document is incorrect"); + Expect.equal(after.Value, "le un", "The updated document is incorrect"); + Expect.equal(after.NumValue, 1, "The updated document is incorrect"); + Expect.isNull(after.Sub, "The updated document should not have a sub-document"); + }), + TestCase("succeeds when no document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await conn.UpdateFullFunc(SqliteDb.TableName, doc => doc.Id, + new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); + }) + }), + TestList("UpdatePartialById", new[] + { + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.UpdatePartialById(SqliteDb.TableName, "one", new { NumValue = 44 }); + var after = await conn.FindById(SqliteDb.TableName, "one"); + Expect.isNotNull(after, "There should have been a document returned post-update"); + Expect.equal(after.Id, "one", "The updated document is not correct"); + Expect.equal(after.NumValue, 44, "The updated document is not correct"); + }), + TestCase("succeeds when no document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await conn.UpdatePartialById(SqliteDb.TableName, "test", new { Foo = "green" }); + }) + }), + TestList("UpdatePartialByField", new[] + { + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "purple", + new { NumValue = 77 }); + var after = await conn.CountByField(SqliteDb.TableName, "NumValue", Op.EQ, 77); + Expect.equal(after, 2L, "There should have been 2 documents returned"); + }), + TestCase("succeeds when no document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var before = await conn.FindAll(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await conn.UpdatePartialByField(SqliteDb.TableName, "Value", Op.EQ, "burgundy", + new { Foo = "green" }); + }) + }), + TestList("DeleteById", new[] + { + TestCase("succeeds when a document is deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.DeleteById(SqliteDb.TableName, "four"); + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 4L, "There should have been 4 documents remaining"); + }), + TestCase("succeeds when a document is not deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.DeleteById(SqliteDb.TableName, "thirty"); + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); + }) + }), + TestList("DeleteByField", new[] + { + TestCase("succeeds when documents are deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.DeleteByField(SqliteDb.TableName, "Value", Op.NE, "purple"); + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 2L, "There should have been 2 documents remaining"); + }), + TestCase("succeeds when documents are not deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + await LoadDocs(); + + await conn.DeleteByField(SqliteDb.TableName, "Value", Op.EQ, "crimson"); + var remaining = await conn.CountAll(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); + }) + }) + }), + TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:")) }); + + /// + /// All tests for SQLite C# functions and methods + /// + public static readonly Test All = TestList("Sqlite.C#", new[] { Unit, TestSequenced(Integration) }); } diff --git a/src/Tests.CSharp/SqliteDb.cs b/src/Tests.CSharp/SqliteDb.cs index 876ab46..cf7fe5e 100644 --- a/src/Tests.CSharp/SqliteDb.cs +++ b/src/Tests.CSharp/SqliteDb.cs @@ -3,7 +3,7 @@ namespace BitBadger.Documents.Tests; using System; using System.IO; using System.Threading.Tasks; -using static Sqlite; +using Sqlite; /// /// A throwaway SQLite database file, which will be deleted when it goes out of scope diff --git a/src/Tests/Program.fs b/src/Tests/Program.fs index 80749e8..9480cb0 100644 --- a/src/Tests/Program.fs +++ b/src/Tests/Program.fs @@ -7,7 +7,7 @@ let allTests = [ CommonTests.all CommonCSharpTests.Unit SqliteTests.all - testSequenced SqliteCSharpTests.Integration ] + SqliteCSharpTests.All ] [] let main args = runTestsWithCLIArgs [] args allTests