From d993f7178844403e9866cd34e47c6a541715c9c2 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Fri, 16 Aug 2024 22:54:27 -0400 Subject: [PATCH] Reorg SQLite tests --- src/Tests.CSharp/SqliteCSharpTests.cs | 1283 ++++++++++++------------ src/Tests/SqliteTests.fs | 1322 +++++++++++++------------ 2 files changed, 1348 insertions(+), 1257 deletions(-) diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index e0c534e..13cc1f3 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -1,6 +1,5 @@ using Expecto.CSharp; using Expecto; -using Microsoft.Data.Sqlite; using Microsoft.FSharp.Core; using BitBadger.Documents.Sqlite; @@ -14,123 +13,125 @@ using static Runner; public static class SqliteCSharpTests { /// - /// Unit tests for the SQLite library + /// Unit tests for the Query module of the SQLite library /// - private static readonly Test Unit = TestList("Unit", + private static readonly Test QueryTests = TestList("Query", [ - TestList("Query", + TestList("WhereByFields", [ - TestList("WhereByFields", - [ - TestCase("succeeds for a single field when a logical operator is passed", () => - { - Expect.equal( - Sqlite.Query.WhereByFields(FieldMatch.Any, - [Field.GT("theField", 0).WithParameterName("@test")]), - "data->>'theField' > @test", "WHERE clause not correct"); - }), - TestCase("succeeds for a single field when an existence operator is passed", () => - { - Expect.equal(Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]), - "data->>'thatField' IS NULL", "WHERE clause not correct"); - }), - TestCase("succeeds for a single field when a between operator is passed", () => - { - Expect.equal( - Sqlite.Query.WhereByFields(FieldMatch.All, - [Field.BT("aField", 50, 99).WithParameterName("@range")]), - "data->>'aField' BETWEEN @rangemin AND @rangemax", "WHERE clause not correct"); - }), - TestCase("succeeds for all multiple fields with logical operators", () => - { - Expect.equal( - Sqlite.Query.WhereByFields(FieldMatch.All, - [Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]), - "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct"); - }), - TestCase("succeeds for any multiple fields with an existence operator", () => - { - Expect.equal( - Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField"), Field.GE("thisField", 18)]), - "data->>'thatField' IS NULL OR data->>'thisField' >= @field0", "WHERE clause not correct"); - }), - TestCase("succeeds for all multiple fields with between operators", () => - { - Expect.equal( - Sqlite.Query.WhereByFields(FieldMatch.All, - [Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]), - "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max", - "WHERE clause not correct"); - }) - ]), - TestCase("WhereById succeeds", () => + TestCase("succeeds for a single field when a logical operator is passed", () => { - Expect.equal(Sqlite.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct"); + Expect.equal( + Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.GT("theField", 0).WithParameterName("@test")]), + "data->>'theField' > @test", "WHERE clause not correct"); }), - TestCase("Patch succeeds", () => + TestCase("succeeds for a single field when an existence operator is passed", () => { - Expect.equal(Sqlite.Query.Patch(SqliteDb.TableName), - $"UPDATE {SqliteDb.TableName} SET data = json_patch(data, json(@data))", "Patch query not correct"); + Expect.equal(Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField")]), + "data->>'thatField' IS NULL", "WHERE clause not correct"); }), - TestCase("RemoveFields succeeds", () => + TestCase("succeeds for a single field when a between operator is passed", () => { - Expect.equal(Sqlite.Query.RemoveFields(SqliteDb.TableName, [new("@a", "a"), new("@b", "b")]), - $"UPDATE {SqliteDb.TableName} SET data = json_remove(data, @a, @b)", - "Field removal query not correct"); + Expect.equal( + Sqlite.Query.WhereByFields(FieldMatch.All, + [Field.BT("aField", 50, 99).WithParameterName("@range")]), + "data->>'aField' BETWEEN @rangemin AND @rangemax", "WHERE clause not correct"); }), - TestCase("ById succeeds", () => + TestCase("succeeds for all multiple fields with logical operators", () => { - Expect.equal(Sqlite.Query.ById("test", "14"), "test WHERE data->>'Id' = @id", - "By-ID query not correct"); + Expect.equal( + Sqlite.Query.WhereByFields(FieldMatch.All, [Field.EQ("theFirst", "1"), Field.EQ("numberTwo", "2")]), + "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1", "WHERE clause not correct"); }), - TestCase("ByFields succeeds", () => + TestCase("succeeds for any multiple fields with an existence operator", () => { - Expect.equal(Sqlite.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]), - "unit WHERE data->>'That' > @field0", "By-Field query not correct"); + Expect.equal( + Sqlite.Query.WhereByFields(FieldMatch.Any, [Field.NEX("thatField"), Field.GE("thisField", 18)]), + "data->>'thatField' IS NULL OR data->>'thisField' >= @field0", "WHERE clause not correct"); }), - TestCase("Definition.EnsureTable succeeds", () => + TestCase("succeeds for all multiple fields with between operators", () => { - Expect.equal(Sqlite.Query.Definition.EnsureTable("tbl"), - "CREATE TABLE IF NOT EXISTS tbl (data TEXT NOT NULL)", "CREATE TABLE statement not correct"); + Expect.equal( + Sqlite.Query.WhereByFields(FieldMatch.All, + [Field.BT("aField", 50, 99), Field.BT("anotherField", "a", "b")]), + "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max", + "WHERE clause not correct"); }) ]), - TestList("Parameters", - [ - 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"); - }), -#pragma warning disable CS0618 - TestCase("AddField succeeds when adding a parameter", () => - { - var paramList = Parameters.AddField("@field", Field.EQ("it", 99), []).ToList(); - Expect.hasLength(paramList, 1, "There should have been a parameter added"); - var theParam = paramList[0]; - Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect"); - Expect.equal(theParam.Value, 99, "The parameter value is incorrect"); - }), - TestCase("AddField succeeds when not adding a parameter", () => - { - var paramSeq = Parameters.AddField("@it", Field.EX("Coffee"), []); - Expect.isEmpty(paramSeq, "There should not have been any parameters added"); - }), -#pragma warning restore CS0618 - TestCase("None succeeds", () => - { - Expect.isEmpty(Parameters.None, "The parameter list should have been empty"); - }) - ]) - // Results are exhaustively executed in the context of other tests + TestCase("WhereById succeeds", () => + { + Expect.equal(Sqlite.Query.WhereById("@id"), "data->>'Id' = @id", "WHERE clause not correct"); + }), + TestCase("Patch succeeds", () => + { + Expect.equal(Sqlite.Query.Patch(SqliteDb.TableName), + $"UPDATE {SqliteDb.TableName} SET data = json_patch(data, json(@data))", "Patch query not correct"); + }), + TestCase("RemoveFields succeeds", () => + { + Expect.equal(Sqlite.Query.RemoveFields(SqliteDb.TableName, [new("@a", "a"), new("@b", "b")]), + $"UPDATE {SqliteDb.TableName} SET data = json_remove(data, @a, @b)", + "Field removal query not correct"); + }), + TestCase("ById succeeds", () => + { + Expect.equal(Sqlite.Query.ById("test", "14"), "test WHERE data->>'Id' = @id", "By-ID query not correct"); + }), + TestCase("ByFields succeeds", () => + { + Expect.equal(Sqlite.Query.ByFields("unit", FieldMatch.Any, [Field.GT("That", 14)]), + "unit WHERE data->>'That' > @field0", "By-Field query not correct"); + }), + TestCase("Definition.EnsureTable succeeds", () => + { + Expect.equal(Sqlite.Query.Definition.EnsureTable("tbl"), + "CREATE TABLE IF NOT EXISTS tbl (data TEXT NOT NULL)", "CREATE TABLE statement not correct"); + }) ]); + /// + /// Unit tests for the Parameters module of the SQLite library + /// + private static readonly Test ParametersTests = TestList("Parameters", + [ + 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"); + }), +#pragma warning disable CS0618 + TestCase("AddField succeeds when adding a parameter", () => + { + var paramList = Parameters.AddField("@field", Field.EQ("it", 99), []).ToList(); + Expect.hasLength(paramList, 1, "There should have been a parameter added"); + var theParam = paramList[0]; + Expect.equal(theParam.ParameterName, "@field", "The parameter name is incorrect"); + Expect.equal(theParam.Value, 99, "The parameter value is incorrect"); + }), + TestCase("AddField succeeds when not adding a parameter", () => + { + var paramSeq = Parameters.AddField("@it", Field.EX("Coffee"), []); + Expect.isEmpty(paramSeq, "There should not have been any parameters added"); + }), +#pragma warning restore CS0618 + TestCase("None succeeds", () => + { + Expect.isEmpty(Parameters.None, "The parameter list should have been empty"); + }) + ]); + + // Results are exhaustively executed in the context of other tests + + /// + /// Documents used for integration tests + /// private static readonly List TestDocuments = [ new() { Id = "one", Value = "FIRST!", NumValue = 0 }, @@ -148,144 +149,158 @@ public static class SqliteCSharpTests foreach (var doc in TestDocuments) await Document.Insert(SqliteDb.TableName, doc); } - private static readonly Test Integration = TestList("Integration", - [ - TestCase("Configuration.UseConnectionString succeeds", () => + /// + /// Integration tests for the Configuration module of the SQLite library + /// + private static readonly Test ConfigurationTests = TestCase("Configuration.UseConnectionString succeeds", () => + { + try { - try + 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 + { + Sqlite.Configuration.UseConnectionString("Data Source=:memory:"); + } + }); + + /// + /// Integration tests for the Custom module of the SQLite library + /// + private static readonly Test CustomTests = TestList("Custom", + [ + TestList("Single", + [ + TestCase("succeeds when a row is found", async () => { - 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 + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var doc = await Custom.Single($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id", + [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 () => { - Sqlite.Configuration.UseConnectionString("Data Source=:memory:"); + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var doc = await Custom.Single($"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id", + [Parameters.Id("eighty")], Results.FromData); + Expect.isNull(doc, "There should not have been a document returned"); + }) + ]), + TestList("List", + [ + TestCase("succeeds when data is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var docs = await Custom.List(Query.Find(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 LoadDocs(); + + var docs = await Custom.List( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", [new("@value", 100)], + Results.FromData); + Expect.isEmpty(docs, "There should have been no documents returned"); + }) + ]), + TestList("NonQuery", + [ + TestCase("succeeds when operating on data", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Custom.NonQuery($"DELETE FROM {SqliteDb.TableName}", Parameters.None); + + var remaining = await Count.All(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 LoadDocs(); + + await Custom.NonQuery($"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", + [new("@value", 100)]); + + var remaining = await Count.All(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table"); + }) + ]), + TestCase("Scalar succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + + var nbr = await Custom.Scalar("SELECT 5 AS test_value", Parameters.None, rdr => rdr.GetInt32(0)); + Expect.equal(nbr, 5, "The query should have returned the number 5"); + }) + ]); + + /// + /// Integration tests for the Definition module of the SQLite library + /// + private static readonly Test DefinitionTests = TestList("Definition", + [ + TestCase("EnsureTable succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + + 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 Definition.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"); + return; + + async ValueTask ItExists(string name) + { + return await Custom.Scalar($"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it", + [new("@name", name)], Results.ToExists); } }), - TestList("Custom", - [ - TestList("Single", - [ - TestCase("succeeds when a row is found", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); + TestCase("EnsureFieldIndex succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); - var doc = await Custom.Single($"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 LoadDocs(); + var exists = await IndexExists(); + Expect.isFalse(exists, "The index should not exist already"); - var doc = await Custom.Single($"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("List", - [ - TestCase("succeeds when data is found", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); + await Definition.EnsureTable("ensured"); + await Definition.EnsureFieldIndex("ensured", "test", ["Id", "Category"]); + exists = await IndexExists(); + Expect.isTrue(exists, "The index should now exist"); + return; - var docs = await Custom.List(Query.Find(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 LoadDocs(); + Task IndexExists() => Custom.Scalar( + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it", + Parameters.None, Results.ToExists); + }) + ]); - var docs = await Custom.List( - $"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("NonQuery", - [ - TestCase("succeeds when operating on data", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Custom.NonQuery($"DELETE FROM {SqliteDb.TableName}", Parameters.None); - - var remaining = await Count.All(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 LoadDocs(); - - await Custom.NonQuery($"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", - new[] { new SqliteParameter("@value", 100) }); - - var remaining = await Count.All(SqliteDb.TableName); - Expect.equal(remaining, 5L, "There should be 5 documents remaining in the table"); - }) - ]), - TestCase("Scalar succeeds", async () => - { - await using var db = await SqliteDb.BuildDb(); - - var nbr = await Custom.Scalar("SELECT 5 AS test_value", Parameters.None, rdr => rdr.GetInt32(0)); - Expect.equal(nbr, 5, "The query should have returned the number 5"); - }) - ]), - TestList("Definition", - [ - TestCase("EnsureTable succeeds", async () => - { - await using var db = await SqliteDb.BuildDb(); - - 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 Definition.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"); - return; - - async ValueTask ItExists(string name) - { - return await Custom.Scalar( - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it", - new SqliteParameter[] { new("@name", name) }, Results.ToExists); - } - }), - TestCase("EnsureFieldIndex succeeds", async () => - { - await using var db = await SqliteDb.BuildDb(); - - var exists = await IndexExists(); - Expect.isFalse(exists, "The index should not exist already"); - - await Definition.EnsureTable("ensured"); - await Definition.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" }); - exists = await IndexExists(); - Expect.isTrue(exists, "The index should now exist"); - return; - - Task IndexExists() => Custom.Scalar( - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it", - Parameters.None, Results.ToExists); - }) - ]), - TestList("Document.Insert", + /// + /// Integration tests for the Document module of the SQLite library + /// + private static readonly Test DocumentTests = TestList("Document", + [ + TestList("Insert", [ TestCase("succeeds", async () => { @@ -344,401 +359,443 @@ public static class SqliteCSharpTests 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"); }) - ]), - TestList("Count", + ]) + ]); + + /// + /// Integration tests for the Count module of the SQLite library + /// + private static readonly Test CountTests = TestList("Count", + [ + TestCase("All succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var theCount = await Count.All(SqliteDb.TableName); + Expect.equal(theCount, 5L, "There should have been 5 matching documents"); + }), + TestList("ByFields", [ - TestCase("All succeeds", async () => + TestCase("succeeds for numeric range", async () => { await using var db = await SqliteDb.BuildDb(); await LoadDocs(); - var theCount = await Count.All(SqliteDb.TableName); - Expect.equal(theCount, 5L, "There should have been 5 matching documents"); + var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.BT("NumValue", 10, 20)]); + Expect.equal(theCount, 3L, "There should have been 3 matching documents"); }), - TestList("ByFields", - [ - TestCase("succeeds for numeric range", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); + TestCase("succeeds for non-numeric range", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); - var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.BT("NumValue", 10, 20)]); - Expect.equal(theCount, 3L, "There should have been 3 matching documents"); - }), - TestCase("succeeds for non-numeric range", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.BT("Value", "aardvark", "apple")]); - Expect.equal(theCount, 1L, "There should have been 1 matching document"); - }) - ]) - ]), - TestList("Exists", - [ - TestList("ById", - [ - TestCase("succeeds when a document exists", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var exists = await Exists.ById(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 LoadDocs(); - - var exists = await Exists.ById(SqliteDb.TableName, "seven"); - Expect.isFalse(exists, "There should not have been an existing document"); - }) - ]), - TestList("ByFields", - [ - TestCase("succeeds when documents exist", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.GE("NumValue", 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 LoadDocs(); - - var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.EQ("Nothing", "none")]); - Expect.isFalse(exists, "There should not have been any existing documents"); - }) - ]) - ]), - TestList("Find", - [ - TestList("All", - [ - TestCase("succeeds when there is data", async () => - { - await using var db = await SqliteDb.BuildDb(); - - 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"); - }), - TestCase("succeeds when there is no data", async () => - { - await using var db = await SqliteDb.BuildDb(); - var results = await Find.All(SqliteDb.TableName); - Expect.isEmpty(results, "There should have been no documents returned"); - }) - ]), - TestList("ById", - [ - 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"); - 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 LoadDocs(); - - var doc = await Find.ById(SqliteDb.TableName, "twenty two"); - Expect.isNull(doc, "There should not have been a document returned"); - }) - ]), - TestList("ByFields", - [ - TestCase("succeeds when documents are found", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var docs = await Find.ByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.GT("NumValue", 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 LoadDocs(); - - var docs = await Find.ByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.EQ("Value", "mauve")]); - Expect.isEmpty(docs, "There should have been no documents returned"); - }) - ]), - TestList("FirstByFields", - [ - TestCase("succeeds when a document is found", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.EQ("Value", "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 LoadDocs(); - - var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.EQ("Sub.Foo", "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 LoadDocs(); - - var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, - [Field.EQ("Value", "absent")]); - Expect.isNull(doc, "There should not have been a document returned"); - }) - ]) - ]), - TestList("Update", - [ - TestList("ById", - [ - TestCase("succeeds when a document is updated", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } }; - await Update.ById(SqliteDb.TableName, "one", testDoc); - var after = await Find.ById(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(); - - var before = await Find.All(SqliteDb.TableName); - Expect.isEmpty(before, "There should have been no documents returned"); - - // This not raising an exception is the test - await Update.ById(SqliteDb.TableName, "test", - new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); - }) - ]), - TestList("ByFunc", - [ - TestCase("succeeds when a document is updated", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Update.ByFunc(SqliteDb.TableName, doc => doc.Id, - new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); - var after = await Find.ById(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(); - - var before = await Find.All(SqliteDb.TableName); - Expect.isEmpty(before, "There should have been no documents returned"); - - // This not raising an exception is the test - await Update.ByFunc(SqliteDb.TableName, doc => doc.Id, - new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); - }) - ]), - ]), - TestList("Patch", - [ - TestList("ById", - [ - TestCase("succeeds when a document is updated", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Patch.ById(SqliteDb.TableName, "one", new { NumValue = 44 }); - var after = await Find.ById(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(); - - var before = await Find.All(SqliteDb.TableName); - Expect.isEmpty(before, "There should have been no documents returned"); - - // This not raising an exception is the test - await Patch.ById(SqliteDb.TableName, "test", new { Foo = "green" }); - }) - ]), - TestList("ByFields", - [ - TestCase("succeeds when a document is updated", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], - new { NumValue = 77 }); - var after = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 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(); - - var before = await Find.All(SqliteDb.TableName); - Expect.isEmpty(before, "There should have been no documents returned"); - - // This not raising an exception is the test - await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], - new { Foo = "green" }); - }) - ]) - ]), - TestList("RemoveFields", - [ - TestList("ById", - [ - TestCase("succeeds when fields are removed", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await RemoveFields.ById(SqliteDb.TableName, "two", new[] { "Sub", "Value" }); - var updated = await Find.ById(SqliteDb.TableName, "two"); - Expect.isNotNull(updated, "The updated document should have been retrieved"); - Expect.equal(updated.Value, "", "The string value should have been removed"); - Expect.isNull(updated.Sub, "The sub-document should have been removed"); - }), - TestCase("succeeds when a field is not removed", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - // This not raising an exception is the test - await RemoveFields.ById(SqliteDb.TableName, "two", new[] { "AFieldThatIsNotThere" }); - }), - TestCase("succeeds when no document is matched", async () => - { - await using var db = await SqliteDb.BuildDb(); - - // This not raising an exception is the test - await RemoveFields.ById(SqliteDb.TableName, "two", new[] { "Value" }); - }) - ]), - TestList("ByFields", - [ - TestCase("succeeds when a field is removed", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], - new[] { "Sub" }); - var updated = await Find.ById(SqliteDb.TableName, "four"); - Expect.isNotNull(updated, "The updated document should have been retrieved"); - Expect.isNull(updated.Sub, "The sub-document should have been removed"); - }), - TestCase("succeeds when a field is not removed", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - // This not raising an exception is the test - await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], - new[] { "Nothing" }); - }), - TestCase("succeeds when no document is matched", async () => - { - await using var db = await SqliteDb.BuildDb(); - - // This not raising an exception is the test - await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")], - new[] { "Value" }); - }) - ]) - ]), - TestList("Delete", - [ - TestList("ById", - [ - TestCase("succeeds when a document is deleted", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Delete.ById(SqliteDb.TableName, "four"); - var remaining = await Count.All(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 LoadDocs(); - - await Delete.ById(SqliteDb.TableName, "thirty"); - var remaining = await Count.All(SqliteDb.TableName); - Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); - }) - ]), - TestList("ByFields", - [ - TestCase("succeeds when documents are deleted", async () => - { - await using var db = await SqliteDb.BuildDb(); - await LoadDocs(); - - await Delete.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]); - var remaining = await Count.All(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 LoadDocs(); - - await Delete.ByFields(SqliteDb.TableName, FieldMatch.All, [Field.EQ("Value", "crimson")]); - var remaining = await Count.All(SqliteDb.TableName); - Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); - }) - ]) - ]), - TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:")) + var theCount = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.BT("Value", "aardvark", "apple")]); + Expect.equal(theCount, 1L, "There should have been 1 matching document"); + }) + ]) ]); + /// + /// Integration tests for the Exists module of the SQLite library + /// + private static readonly Test ExistsTests = TestList("Exists", + [ + TestList("ById", + [ + TestCase("succeeds when a document exists", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var exists = await Exists.ById(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 LoadDocs(); + + var exists = await Exists.ById(SqliteDb.TableName, "seven"); + Expect.isFalse(exists, "There should not have been an existing document"); + }) + ]), + TestList("ByFields", + [ + TestCase("succeeds when documents exist", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.GE("NumValue", 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 LoadDocs(); + + var exists = await Exists.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Nothing", "none")]); + Expect.isFalse(exists, "There should not have been any existing documents"); + }) + ]) + ]); + + /// + /// Integration tests for the Find module of the SQLite library + /// + private static readonly Test FindTests = TestList("Find", + [ + TestList("All", + [ + TestCase("succeeds when there is data", async () => + { + await using var db = await SqliteDb.BuildDb(); + + 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"); + }), + TestCase("succeeds when there is no data", async () => + { + await using var db = await SqliteDb.BuildDb(); + var results = await Find.All(SqliteDb.TableName); + Expect.isEmpty(results, "There should have been no documents returned"); + }) + ]), + TestList("ById", + [ + 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"); + 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 LoadDocs(); + + var doc = await Find.ById(SqliteDb.TableName, "twenty two"); + Expect.isNull(doc, "There should not have been a document returned"); + }) + ]), + TestList("ByFields", + [ + TestCase("succeeds when documents are found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var docs = await Find.ByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.GT("NumValue", 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 LoadDocs(); + + var docs = await Find.ByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Value", "mauve")]); + Expect.isEmpty(docs, "There should have been no documents returned"); + }) + ]), + TestList("FirstByFields", + [ + TestCase("succeeds when a document is found", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Value", "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 LoadDocs(); + + var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Sub.Foo", "green")]); + Expect.isNotNull(doc, "There should have been a document returned"); + Expect.contains(["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 LoadDocs(); + + var doc = await Find.FirstByFields(SqliteDb.TableName, FieldMatch.Any, + [Field.EQ("Value", "absent")]); + Expect.isNull(doc, "There should not have been a document returned"); + }) + ]) + ]); + + /// + /// Integration tests for the Update module of the SQLite library + /// + private static readonly Test UpdateTests = TestList("Update", + [ + TestList("ById", + [ + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + var testDoc = new JsonDocument { Id = "one", Sub = new() { Foo = "blue", Bar = "red" } }; + await Update.ById(SqliteDb.TableName, "one", testDoc); + var after = await Find.ById(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(); + + var before = await Find.All(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await Update.ById(SqliteDb.TableName, "test", + new JsonDocument { Id = "x", Sub = new() { Foo = "blue", Bar = "red" } }); + }) + ]), + TestList("ByFunc", + [ + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Update.ByFunc(SqliteDb.TableName, doc => doc.Id, + new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); + var after = await Find.ById(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(); + + var before = await Find.All(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await Update.ByFunc(SqliteDb.TableName, doc => doc.Id, + new JsonDocument { Id = "one", Value = "le un", NumValue = 1 }); + }) + ]), + ]); + + /// + /// Integration tests for the Patch module of the SQLite library + /// + private static readonly Test PatchTests = TestList("Patch", + [ + TestList("ById", + [ + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Patch.ById(SqliteDb.TableName, "one", new { NumValue = 44 }); + var after = await Find.ById(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(); + + var before = await Find.All(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await Patch.ById(SqliteDb.TableName, "test", new { Foo = "green" }); + }) + ]), + TestList("ByFields", + [ + TestCase("succeeds when a document is updated", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "purple")], + new { NumValue = 77 }); + var after = await Count.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 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(); + + var before = await Find.All(SqliteDb.TableName); + Expect.isEmpty(before, "There should have been no documents returned"); + + // This not raising an exception is the test + await Patch.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("Value", "burgundy")], + new { Foo = "green" }); + }) + ]) + ]); + + /// + /// Integration tests for the RemoveFields module of the SQLite library + /// + private static readonly Test RemoveFieldsTests = TestList("RemoveFields", + [ + TestList("ById", + [ + TestCase("succeeds when fields are removed", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ById(SqliteDb.TableName, "two", ["Sub", "Value"]); + var updated = await Find.ById(SqliteDb.TableName, "two"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.equal(updated.Value, "", "The string value should have been removed"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ById(SqliteDb.TableName, "two", ["AFieldThatIsNotThere"]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = await SqliteDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ById(SqliteDb.TableName, "two", ["Value"]); + }) + ]), + TestList("ByFields", + [ + TestCase("succeeds when a field is removed", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], ["Sub"]); + var updated = await Find.ById(SqliteDb.TableName, "four"); + Expect.isNotNull(updated, "The updated document should have been retrieved"); + Expect.isNull(updated.Sub, "The sub-document should have been removed"); + }), + TestCase("succeeds when a field is not removed", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + // This not raising an exception is the test + await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.EQ("NumValue", 17)], + ["Nothing"]); + }), + TestCase("succeeds when no document is matched", async () => + { + await using var db = await SqliteDb.BuildDb(); + + // This not raising an exception is the test + await RemoveFields.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Abracadabra", "apple")], + ["Value"]); + }) + ]) + ]); + + /// + /// Integration tests for the Delete module of the SQLite library + /// + private static readonly Test DeleteTests = TestList("Delete", + [ + TestList("ById", + [ + TestCase("succeeds when a document is deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Delete.ById(SqliteDb.TableName, "four"); + var remaining = await Count.All(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 LoadDocs(); + + await Delete.ById(SqliteDb.TableName, "thirty"); + var remaining = await Count.All(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); + }) + ]), + TestList("ByFields", + [ + TestCase("succeeds when documents are deleted", async () => + { + await using var db = await SqliteDb.BuildDb(); + await LoadDocs(); + + await Delete.ByFields(SqliteDb.TableName, FieldMatch.Any, [Field.NE("Value", "purple")]); + var remaining = await Count.All(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 LoadDocs(); + + await Delete.ByFields(SqliteDb.TableName, FieldMatch.All, [Field.EQ("Value", "crimson")]); + var remaining = await Count.All(SqliteDb.TableName); + Expect.equal(remaining, 5L, "There should have been 5 documents remaining"); + }) + ]) + ]); + /// /// All tests for SQLite C# functions and methods /// [Tests] - public static readonly Test All = TestList("Sqlite.C#", [Unit, TestSequenced(Integration)]); + public static readonly Test All = TestList("Sqlite.C#", + [ + TestList("Unit", [QueryTests, ParametersTests]), + TestSequenced(TestList("Integration", + [ + ConfigurationTests, + CustomTests, + DefinitionTests, + DocumentTests, + CountTests, + ExistsTests, + FindTests, + UpdateTests, + PatchTests, + RemoveFieldsTests, + DeleteTests, + TestCase("Clean up database", () => Sqlite.Configuration.UseConnectionString("data source=:memory:")) + ])) + ]); } diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs index c6a0ee3..1006e25 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -10,651 +10,685 @@ open Types #nowarn "0044" -/// Unit tests for the SQLite library -let unitTests = - testList "Unit" [ - testList "Query" [ - testList "whereByFields" [ - test "succeeds for a single field when a logical operator is passed" { - Expect.equal - (Query.whereByFields Any [ { Field.GT "theField" 0 with ParameterName = Some "@test" } ]) - "data->>'theField' > @test" - "WHERE clause not correct" - } - test "succeeds for a single field when an existence operator is passed" { - Expect.equal - (Query.whereByFields Any [ Field.NEX "thatField" ]) - "data->>'thatField' IS NULL" - "WHERE clause not correct" - } - test "succeeds for a single field when a between operator is passed" { - Expect.equal - (Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ]) - "data->>'aField' BETWEEN @rangemin AND @rangemax" - "WHERE clause not correct" - } - test "succeeds for all multiple fields with logical operators" { - Expect.equal - (Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ]) - "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1" - "WHERE clause not correct" - } - test "succeeds for any multiple fields with an existence operator" { - Expect.equal - (Query.whereByFields Any [ Field.NEX "thatField"; Field.GE "thisField" 18 ]) - "data->>'thatField' IS NULL OR data->>'thisField' >= @field0" - "WHERE clause not correct" - } - test "succeeds for all multiple fields with between operators" { - Expect.equal - (Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ]) - "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max" - "WHERE clause not correct" - } - ] - test "whereById succeeds" { - Expect.equal (Query.whereById "@id") "data->>'Id' = @id" "WHERE clause not correct" - } - test "patch succeeds" { - Expect.equal - (Query.patch SqliteDb.TableName) - $"UPDATE {SqliteDb.TableName} SET data = json_patch(data, json(@data))" - "Patch query not correct" - } - test "removeFields succeeds" { - Expect.equal - (Query.removeFields SqliteDb.TableName [ SqliteParameter("@a", "a"); SqliteParameter("@b", "b") ]) - $"UPDATE {SqliteDb.TableName} SET data = json_remove(data, @a, @b)" - "Field removal query not correct" - } - test "byId succeeds" { - Expect.equal (Query.byId "test" "14") "test WHERE data->>'Id' = @id" "By-ID query not correct" - } - test "byFields succeeds" { - Expect.equal - (Query.byFields "unit" Any [ Field.GT "That" 14 ]) - "unit WHERE data->>'That' > @field0" - "By-Field query not correct" - } - test "Definition.ensureTable succeeds" { - Expect.equal - (Query.Definition.ensureTable "tbl") - "CREATE TABLE IF NOT EXISTS tbl (data TEXT NOT NULL)" - "CREATE TABLE statement not correct" - } - ] - testList "Parameters" [ - test "idParam succeeds" { - let theParam = idParam 7 - Expect.equal theParam.ParameterName "@id" "The parameter name is incorrect" - Expect.equal theParam.Value "7" "The parameter value is incorrect" - } - test "jsonParam succeeds" { - let theParam = jsonParam "@test" {| Nice = "job" |} - Expect.equal theParam.ParameterName "@test" "The parameter name is incorrect" - Expect.equal theParam.Value """{"Nice":"job"}""" "The parameter value is incorrect" - } - testList "addFieldParam" [ - test "succeeds when adding a parameter" { - let paramList = addFieldParam "@field" (Field.EQ "it" 99) [] - Expect.hasLength paramList 1 "There should have been a parameter added" - let theParam = Seq.head paramList - Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect" - Expect.equal theParam.Value 99 "The parameter value is incorrect" - } - test "succeeds when not adding a parameter" { - let paramList = addFieldParam "@it" (Field.NEX "Coffee") [] - Expect.isEmpty paramList "There should not have been any parameters added" - } - ] - test "noParams succeeds" { - Expect.isEmpty noParams "The parameter list should have been empty" - } - ] - // Results are exhaustively executed in the context of other tests - ] +(** UNIT TESTS **) -/// These tests each use a fresh copy of a SQLite database -let integrationTests = - let documents = [ - { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None } - { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } } - { Id = "three"; Value = ""; NumValue = 4; Sub = None } - { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } } - { Id = "five"; Value = "purple"; NumValue = 18; Sub = None } - ] - let loadDocs () = backgroundTask { - for doc in documents do do! insert SqliteDb.TableName doc - } - testList "Integration" [ - testList "Configuration" [ - test "useConnectionString / connectionString succeed" { - try - Configuration.useConnectionString "Data Source=test.db" - Expect.equal - Configuration.connectionString - (Some "Data Source=test.db;Foreign Keys=True") - "Connection string incorrect" - finally - Configuration.useConnectionString "Data Source=:memory:" - } - test "useSerializer succeeds" { - try - Configuration.useSerializer - { new IDocumentSerializer with - member _.Serialize<'T>(it: 'T) : string = """{"Overridden":true}""" - member _.Deserialize<'T>(it: string) : 'T = Unchecked.defaultof<'T> - } - - let serialized = Configuration.serializer().Serialize { Foo = "howdy"; Bar = "bye"} - Expect.equal serialized """{"Overridden":true}""" "Specified serializer was not used" - - let deserialized = Configuration.serializer().Deserialize """{"Something":"here"}""" - Expect.isNull deserialized "Specified serializer should have returned null" - finally - Configuration.useSerializer DocumentSerializer.``default`` - } - test "serializer returns configured serializer" { - Expect.isTrue (obj.ReferenceEquals(DocumentSerializer.``default``, Configuration.serializer ())) - "Serializer should have been the same" - } - test "useIdField / idField succeeds" { - Expect.equal (Configuration.idField ()) "Id" "The default configured ID field was incorrect" - Configuration.useIdField "id" - Expect.equal (Configuration.idField ()) "id" "useIdField did not set the ID field" - Configuration.useIdField "Id" - } - ] - testList "Custom" [ - testList "single" [ - testTask "succeeds when a row is found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = - Custom.single - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id" - [ SqliteParameter("@id", "one") ] - fromData - Expect.isSome doc "There should have been a document returned" - Expect.equal doc.Value.Id "one" "The incorrect document was returned" - } - testTask "succeeds when a row is not found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = - Custom.single - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id" - [ SqliteParameter("@id", "eighty") ] - fromData - Expect.isNone doc "There should not have been a document returned" - } - ] - testList "list" [ - testTask "succeeds when data is found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! docs = Custom.list (Query.selectFromTable SqliteDb.TableName) [] fromData - Expect.hasCountOf docs 5u (fun _ -> true) "There should have been 5 documents returned" - } - testTask "succeeds when data is not found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! docs = - Custom.list - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" - [ SqliteParameter("@value", 100) ] - fromData - Expect.isEmpty docs "There should have been no documents returned" - } - ] - testList "nonQuery" [ - testTask "succeeds when operating on data" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Custom.nonQuery $"DELETE FROM {SqliteDb.TableName}" [] - - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 0L "There should be no documents remaining in the table" - } - testTask "succeeds when no data matches where clause" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Custom.nonQuery - $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" - [ SqliteParameter("@value", 100) ] - - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 5L "There should be 5 documents remaining in the table" - } - ] - testTask "scalar succeeds" { - use! db = SqliteDb.BuildDb() - - let! nbr = Custom.scalar "SELECT 5 AS test_value" [] _.GetInt32(0) - Expect.equal nbr 5 "The query should have returned the number 5" - } - ] - testList "Definition" [ - testTask "ensureTable succeeds" { - use! db = SqliteDb.BuildDb() - let itExists (name: string) = - Custom.scalar - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" - [ SqliteParameter("@name", name) ] - toExists - - 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" - - do! 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" - } - testTask "ensureFieldIndex succeeds" { - use! db = SqliteDb.BuildDb() - let indexExists () = - Custom.scalar - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it" - [] - toExists - - let! exists = indexExists () - Expect.isFalse exists "The index should not exist already" - - do! Definition.ensureTable "ensured" - do! Definition.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ] - let! exists' = indexExists () - Expect.isTrue exists' "The index should now exist" - } - ] - testList "insert" [ - testTask "succeeds" { - use! db = SqliteDb.BuildDb() - let! before = Find.all SqliteDb.TableName - Expect.equal before [] "There should be no documents in the table" - - let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } } - do! insert SqliteDb.TableName testDoc - let! after = Find.all SqliteDb.TableName - Expect.equal after [ testDoc ] "There should have been one document inserted" - } - testTask "fails for duplicate key" { - use! db = SqliteDb.BuildDb() - do! insert SqliteDb.TableName { emptyDoc with Id = "test" } - Expect.throws - (fun () -> - insert SqliteDb.TableName {emptyDoc with Id = "test" } |> Async.AwaitTask |> Async.RunSynchronously) - "An exception should have been raised for duplicate document ID insert" - } - ] - testList "save" [ - testTask "succeeds when a document is inserted" { - use! db = SqliteDb.BuildDb() - let! before = Find.all SqliteDb.TableName - Expect.equal before [] "There should be no documents in the table" - - let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } - do! save SqliteDb.TableName testDoc - let! after = Find.all SqliteDb.TableName - Expect.equal after [ testDoc ] "There should have been one document inserted" - } - testTask "succeeds when a document is updated" { - use! db = SqliteDb.BuildDb() - let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } - do! insert SqliteDb.TableName testDoc - - let! before = Find.byId SqliteDb.TableName "test" - Expect.isSome before "There should have been a document returned" - Expect.equal before.Value testDoc "The document is not correct" - - let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } } - do! save SqliteDb.TableName upd8Doc - let! after = Find.byId SqliteDb.TableName "test" - Expect.isSome after "There should have been a document returned post-update" - Expect.equal after.Value upd8Doc "The updated document is not correct" - } - ] - testList "Count" [ - testTask "all succeeds" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! theCount = Count.all SqliteDb.TableName - Expect.equal theCount 5L "There should have been 5 matching documents" - } - testList "byFields" [ - testTask "succeeds for a numeric range" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "NumValue" 10 20 ] - Expect.equal theCount 3L "There should have been 3 matching documents" - } - testTask "succeeds for a non-numeric range" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "Value" "aardvark" "apple" ] - Expect.equal theCount 1L "There should have been 1 matching document" - } - ] - ] - testList "Exists" [ - testList "byId" [ - testTask "succeeds when a document exists" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! exists = Exists.byId SqliteDb.TableName "three" - Expect.isTrue exists "There should have been an existing document" - } - testTask "succeeds when a document does not exist" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! exists = Exists.byId SqliteDb.TableName "seven" - Expect.isFalse exists "There should not have been an existing document" - } - ] - testList "byFields" [ - testTask "succeeds when documents exist" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! exists = Exists.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 10 ] - Expect.isTrue exists "There should have been existing documents" - } - testTask "succeeds when no matching documents exist" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! exists = Exists.byFields SqliteDb.TableName Any [ Field.LT "Nothing" "none" ] - Expect.isFalse exists "There should not have been any existing documents" - } - ] - ] - testList "Find" [ - testList "all" [ - testTask "succeeds when there is data" { - use! db = SqliteDb.BuildDb() - - do! insert SqliteDb.TableName { Foo = "one"; Bar = "two" } - do! insert SqliteDb.TableName { Foo = "three"; Bar = "four" } - do! insert SqliteDb.TableName { Foo = "five"; Bar = "six" } - - let! results = Find.all SqliteDb.TableName - let expected = [ - { Foo = "one"; Bar = "two" } - { Foo = "three"; Bar = "four" } - { Foo = "five"; Bar = "six" } - ] - Expect.equal results expected "There should have been 3 documents returned" - } - testTask "succeeds when there is no data" { - use! db = SqliteDb.BuildDb() - let! results = Find.all SqliteDb.TableName - Expect.equal results [] "There should have been no documents returned" - } - ] - testList "byId" [ - testTask "succeeds when a document is found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = Find.byId SqliteDb.TableName "two" - Expect.isTrue (Option.isSome doc) "There should have been a document returned" - Expect.equal doc.Value.Id "two" "The incorrect document was returned" - } - testTask "succeeds when a document is not found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = Find.byId SqliteDb.TableName "three hundred eighty-seven" - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" - } - ] - testList "byFields" [ - testTask "succeeds when documents are found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! docs = Find.byFields SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] - Expect.equal (List.length docs) 2 "There should have been two documents returned" - } - testTask "succeeds when documents are not found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! docs = Find.byFields SqliteDb.TableName Any [ Field.GT "NumValue" 100 ] - Expect.isTrue (List.isEmpty docs) "There should have been no documents returned" - } - ] - testList "firstByFields" [ - testTask "succeeds when a document is found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "another" ] - Expect.isTrue (Option.isSome doc) "There should have been a document returned" - Expect.equal doc.Value.Id "two" "The incorrect document was returned" - } - testTask "succeeds when multiple documents are found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] - Expect.isTrue (Option.isSome doc) "There should have been a document returned" - Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" - } - testTask "succeeds when a document is not found" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] - Expect.isFalse (Option.isSome doc) "There should not have been a document returned" - } - ] - ] - testList "Update" [ - testList "byId" [ - testTask "succeeds when a document is updated" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } } - do! Update.byId SqliteDb.TableName "one" testDoc - let! after = Find.byId SqliteDb.TableName "one" - Expect.isSome after "There should have been a document returned post-update" - Expect.equal after.Value testDoc "The updated document is not correct" - } - testTask "succeeds when no document is updated" { - use! db = SqliteDb.BuildDb() - - let! before = Find.all SqliteDb.TableName - Expect.isEmpty before "There should have been no documents returned" - - // This not raising an exception is the test - do! Update.byId - SqliteDb.TableName - "test" - { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } } - } - ] - testList "byFunc" [ - testTask "succeeds when a document is updated" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Update.byFunc - SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } - let! after = Find.byId SqliteDb.TableName "one" - Expect.isSome after "There should have been a document returned post-update" - Expect.equal - after.Value - { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } - "The updated document is not correct" - } - testTask "succeeds when no document is updated" { - use! db = SqliteDb.BuildDb() - - let! before = Find.all SqliteDb.TableName - Expect.isEmpty before "There should have been no documents returned" - - // This not raising an exception is the test - do! Update.byFunc - SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } - } - ] - ] - testList "Patch" [ - testList "byId" [ - testTask "succeeds when a document is updated" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Patch.byId SqliteDb.TableName "one" {| NumValue = 44 |} - let! after = Find.byId SqliteDb.TableName "one" - Expect.isSome after "There should have been a document returned post-update" - Expect.equal after.Value.NumValue 44 "The updated document is not correct" - } - testTask "succeeds when no document is updated" { - use! db = SqliteDb.BuildDb() - - let! before = Find.all SqliteDb.TableName - Expect.isEmpty before "There should have been no documents returned" - - // This not raising an exception is the test - do! Patch.byId SqliteDb.TableName "test" {| Foo = "green" |} - } - ] - testList "byFields" [ - testTask "succeeds when a document is updated" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} - let! after = Count.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 77 ] - Expect.equal after 2L "There should have been 2 documents returned" - } - testTask "succeeds when no document is updated" { - use! db = SqliteDb.BuildDb() - - let! before = Find.all SqliteDb.TableName - Expect.isEmpty before "There should have been no documents returned" - - // This not raising an exception is the test - do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} - } - ] - ] - testList "RemoveFields" [ - testList "byId" [ - testTask "succeeds when fields is removed" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! RemoveFields.byId SqliteDb.TableName "two" [ "Sub"; "Value" ] - try - let! _ = Find.byId SqliteDb.TableName "two" - Expect.isTrue false "The updated document should have failed to parse" - with - | :? JsonException -> () - | exn as ex -> Expect.isTrue false $"Threw {ex.GetType().Name} ({ex.Message})" - } - testTask "succeeds when a field is not removed" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - // This not raising an exception is the test - do! RemoveFields.byId SqliteDb.TableName "two" [ "AFieldThatIsNotThere" ] - } - testTask "succeeds when no document is matched" { - use! db = SqliteDb.BuildDb() - - // This not raising an exception is the test - do! RemoveFields.byId SqliteDb.TableName "two" [ "Value" ] - } - ] - testList "byFields" [ - testTask "succeeds when a field is removed" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Sub" ] - try - let! _ = Find.byId SqliteDb.TableName "four" - Expect.isTrue false "The updated document should have failed to parse" - with - | :? JsonException -> () - | exn as ex -> Expect.isTrue false $"Threw {ex.GetType().Name} ({ex.Message})" - } - testTask "succeeds when a field is not removed" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - // This not raising an exception is the test - do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Nothing" ] - } - testTask "succeeds when no document is matched" { - use! db = SqliteDb.BuildDb() - - // This not raising an exception is the test - do! RemoveFields.byFields SqliteDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] - } - ] - ] - testList "Delete" [ - testList "byId" [ - testTask "succeeds when a document is deleted" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Delete.byId SqliteDb.TableName "four" - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 4L "There should have been 4 documents remaining" - } - testTask "succeeds when a document is not deleted" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Delete.byId SqliteDb.TableName "thirty" - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 5L "There should have been 5 documents remaining" - } - ] - testList "byFields" [ - testTask "succeeds when documents are deleted" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Delete.byFields SqliteDb.TableName Any [ Field.NE "Value" "purple" ] - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 2L "There should have been 2 documents remaining" - } - testTask "succeeds when documents are not deleted" { - use! db = SqliteDb.BuildDb() - do! loadDocs () - - do! Delete.byFields SqliteDb.TableName Any [ Field.EQ "Value" "crimson" ] - let! remaining = Count.all SqliteDb.TableName - Expect.equal remaining 5L "There should have been 5 documents remaining" - } - ] - ] - test "clean up database" { - Configuration.useConnectionString "data source=:memory:" +/// Unit tests for the Query module of the SQLite library +let queryTests = testList "Query" [ + testList "whereByFields" [ + test "succeeds for a single field when a logical operator is passed" { + Expect.equal + (Query.whereByFields Any [ { Field.GT "theField" 0 with ParameterName = Some "@test" } ]) + "data->>'theField' > @test" + "WHERE clause not correct" + } + test "succeeds for a single field when an existence operator is passed" { + Expect.equal + (Query.whereByFields Any [ Field.NEX "thatField" ]) + "data->>'thatField' IS NULL" + "WHERE clause not correct" + } + test "succeeds for a single field when a between operator is passed" { + Expect.equal + (Query.whereByFields All [ { Field.BT "aField" 50 99 with ParameterName = Some "@range" } ]) + "data->>'aField' BETWEEN @rangemin AND @rangemax" + "WHERE clause not correct" + } + test "succeeds for all multiple fields with logical operators" { + Expect.equal + (Query.whereByFields All [ Field.EQ "theFirst" "1"; Field.EQ "numberTwo" "2" ]) + "data->>'theFirst' = @field0 AND data->>'numberTwo' = @field1" + "WHERE clause not correct" + } + test "succeeds for any multiple fields with an existence operator" { + Expect.equal + (Query.whereByFields Any [ Field.NEX "thatField"; Field.GE "thisField" 18 ]) + "data->>'thatField' IS NULL OR data->>'thisField' >= @field0" + "WHERE clause not correct" + } + test "succeeds for all multiple fields with between operators" { + Expect.equal + (Query.whereByFields All [ Field.BT "aField" 50 99; Field.BT "anotherField" "a" "b" ]) + "data->>'aField' BETWEEN @field0min AND @field0max AND data->>'anotherField' BETWEEN @field1min AND @field1max" + "WHERE clause not correct" } ] - |> testSequenced + test "whereById succeeds" { + Expect.equal (Query.whereById "@id") "data->>'Id' = @id" "WHERE clause not correct" + } + test "patch succeeds" { + Expect.equal + (Query.patch SqliteDb.TableName) + $"UPDATE {SqliteDb.TableName} SET data = json_patch(data, json(@data))" + "Patch query not correct" + } + test "removeFields succeeds" { + Expect.equal + (Query.removeFields SqliteDb.TableName [ SqliteParameter("@a", "a"); SqliteParameter("@b", "b") ]) + $"UPDATE {SqliteDb.TableName} SET data = json_remove(data, @a, @b)" + "Field removal query not correct" + } + test "byId succeeds" { + Expect.equal (Query.byId "test" "14") "test WHERE data->>'Id' = @id" "By-ID query not correct" + } + test "byFields succeeds" { + Expect.equal + (Query.byFields "unit" Any [ Field.GT "That" 14 ]) + "unit WHERE data->>'That' > @field0" + "By-Field query not correct" + } + test "Definition.ensureTable succeeds" { + Expect.equal + (Query.Definition.ensureTable "tbl") + "CREATE TABLE IF NOT EXISTS tbl (data TEXT NOT NULL)" + "CREATE TABLE statement not correct" + } +] -let all = testList "Sqlite" [ unitTests; integrationTests ] +/// Unit tests for the Parameters module of the SQLite library +let parametersTests = testList "Parameters" [ + test "idParam succeeds" { + let theParam = idParam 7 + Expect.equal theParam.ParameterName "@id" "The parameter name is incorrect" + Expect.equal theParam.Value "7" "The parameter value is incorrect" + } + test "jsonParam succeeds" { + let theParam = jsonParam "@test" {| Nice = "job" |} + Expect.equal theParam.ParameterName "@test" "The parameter name is incorrect" + Expect.equal theParam.Value """{"Nice":"job"}""" "The parameter value is incorrect" + } + testList "addFieldParam" [ + test "succeeds when adding a parameter" { + let paramList = addFieldParam "@field" (Field.EQ "it" 99) [] + Expect.hasLength paramList 1 "There should have been a parameter added" + let theParam = Seq.head paramList + Expect.equal theParam.ParameterName "@field" "The parameter name is incorrect" + Expect.equal theParam.Value 99 "The parameter value is incorrect" + } + test "succeeds when not adding a parameter" { + let paramList = addFieldParam "@it" (Field.NEX "Coffee") [] + Expect.isEmpty paramList "There should not have been any parameters added" + } + ] + test "noParams succeeds" { + Expect.isEmpty noParams "The parameter list should have been empty" + } +] +// Results are exhaustively executed in the context of other tests + + +(** INTEGRATION TESTS **) + +/// Documents used for integration tests +let documents = [ + { Id = "one"; Value = "FIRST!"; NumValue = 0; Sub = None } + { Id = "two"; Value = "another"; NumValue = 10; Sub = Some { Foo = "green"; Bar = "blue" } } + { Id = "three"; Value = ""; NumValue = 4; Sub = None } + { Id = "four"; Value = "purple"; NumValue = 17; Sub = Some { Foo = "green"; Bar = "red" } } + { Id = "five"; Value = "purple"; NumValue = 18; Sub = None } +] + +/// Load a table with the test documents +let loadDocs () = backgroundTask { + for doc in documents do do! insert SqliteDb.TableName doc +} + +/// Integration tests for the Configuration module of the SQLite library +let configurationTests = testList "Configuration" [ + test "useConnectionString / connectionString succeed" { + try + Configuration.useConnectionString "Data Source=test.db" + Expect.equal + Configuration.connectionString + (Some "Data Source=test.db;Foreign Keys=True") + "Connection string incorrect" + finally + Configuration.useConnectionString "Data Source=:memory:" + } + test "useSerializer succeeds" { + try + Configuration.useSerializer + { new IDocumentSerializer with + member _.Serialize<'T>(it: 'T) : string = """{"Overridden":true}""" + member _.Deserialize<'T>(it: string) : 'T = Unchecked.defaultof<'T> + } + + let serialized = Configuration.serializer().Serialize { Foo = "howdy"; Bar = "bye"} + Expect.equal serialized """{"Overridden":true}""" "Specified serializer was not used" + + let deserialized = Configuration.serializer().Deserialize """{"Something":"here"}""" + Expect.isNull deserialized "Specified serializer should have returned null" + finally + Configuration.useSerializer DocumentSerializer.``default`` + } + test "serializer returns configured serializer" { + Expect.isTrue (obj.ReferenceEquals(DocumentSerializer.``default``, Configuration.serializer ())) + "Serializer should have been the same" + } + test "useIdField / idField succeeds" { + Expect.equal (Configuration.idField ()) "Id" "The default configured ID field was incorrect" + Configuration.useIdField "id" + Expect.equal (Configuration.idField ()) "id" "useIdField did not set the ID field" + Configuration.useIdField "Id" + } +] + +/// Integration tests for the Custom module of the SQLite library +let customTests = testList "Custom" [ + testList "single" [ + testTask "succeeds when a row is found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = + Custom.single + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id" + [ SqliteParameter("@id", "one") ] + fromData + Expect.isSome doc "There should have been a document returned" + Expect.equal doc.Value.Id "one" "The incorrect document was returned" + } + testTask "succeeds when a row is not found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = + Custom.single + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'Id' = @id" + [ SqliteParameter("@id", "eighty") ] + fromData + Expect.isNone doc "There should not have been a document returned" + } + ] + testList "list" [ + testTask "succeeds when data is found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = Custom.list (Query.find SqliteDb.TableName) [] fromData + Expect.hasCountOf docs 5u (fun _ -> true) "There should have been 5 documents returned" + } + testTask "succeeds when data is not found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = + Custom.list + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" + [ SqliteParameter("@value", 100) ] + fromData + Expect.isEmpty docs "There should have been no documents returned" + } + ] + testList "nonQuery" [ + testTask "succeeds when operating on data" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Custom.nonQuery $"DELETE FROM {SqliteDb.TableName}" [] + + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 0L "There should be no documents remaining in the table" + } + testTask "succeeds when no data matches where clause" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Custom.nonQuery + $"DELETE FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" + [ SqliteParameter("@value", 100) ] + + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 5L "There should be 5 documents remaining in the table" + } + ] + testTask "scalar succeeds" { + use! db = SqliteDb.BuildDb() + + let! nbr = Custom.scalar "SELECT 5 AS test_value" [] _.GetInt32(0) + Expect.equal nbr 5 "The query should have returned the number 5" + } +] + +/// Integration tests for the Definition module of the SQLite library +let definitionTests = testList "Definition" [ + testTask "ensureTable succeeds" { + use! db = SqliteDb.BuildDb() + let itExists (name: string) = + Custom.scalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" + [ SqliteParameter("@name", name) ] + toExists + + 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" + + do! 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" + } + testTask "ensureFieldIndex succeeds" { + use! db = SqliteDb.BuildDb() + let indexExists () = + Custom.scalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it" + [] + toExists + + let! exists = indexExists () + Expect.isFalse exists "The index should not exist already" + + do! Definition.ensureTable "ensured" + do! Definition.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ] + let! exists' = indexExists () + Expect.isTrue exists' "The index should now exist" + } +] + +/// Integration tests for the (auto-opened) Document module of the SQLite library +let documentTests = testList "Document" [ + testList "insert" [ + testTask "succeeds" { + use! db = SqliteDb.BuildDb() + let! before = Find.all SqliteDb.TableName + Expect.equal before [] "There should be no documents in the table" + + let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } } + do! insert SqliteDb.TableName testDoc + let! after = Find.all SqliteDb.TableName + Expect.equal after [ testDoc ] "There should have been one document inserted" + } + testTask "fails for duplicate key" { + use! db = SqliteDb.BuildDb() + do! insert SqliteDb.TableName { emptyDoc with Id = "test" } + Expect.throws + (fun () -> + insert SqliteDb.TableName {emptyDoc with Id = "test" } |> Async.AwaitTask |> Async.RunSynchronously) + "An exception should have been raised for duplicate document ID insert" + } + ] + testList "save" [ + testTask "succeeds when a document is inserted" { + use! db = SqliteDb.BuildDb() + let! before = Find.all SqliteDb.TableName + Expect.equal before [] "There should be no documents in the table" + + let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } + do! save SqliteDb.TableName testDoc + let! after = Find.all SqliteDb.TableName + Expect.equal after [ testDoc ] "There should have been one document inserted" + } + testTask "succeeds when a document is updated" { + use! db = SqliteDb.BuildDb() + let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } + do! insert SqliteDb.TableName testDoc + + let! before = Find.byId SqliteDb.TableName "test" + Expect.isSome before "There should have been a document returned" + Expect.equal before.Value testDoc "The document is not correct" + + let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } } + do! save SqliteDb.TableName upd8Doc + let! after = Find.byId SqliteDb.TableName "test" + Expect.isSome after "There should have been a document returned post-update" + Expect.equal after.Value upd8Doc "The updated document is not correct" + } + ] +] + +/// Integration tests for the Count module of the SQLite library +let countTests = testList "Count" [ + testTask "all succeeds" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! theCount = Count.all SqliteDb.TableName + Expect.equal theCount 5L "There should have been 5 matching documents" + } + testList "byFields" [ + testTask "succeeds for a numeric range" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "NumValue" 10 20 ] + Expect.equal theCount 3L "There should have been 3 matching documents" + } + testTask "succeeds for a non-numeric range" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! theCount = Count.byFields SqliteDb.TableName Any [ Field.BT "Value" "aardvark" "apple" ] + Expect.equal theCount 1L "There should have been 1 matching document" + } + ] +] + +/// Integration tests for the Exists module of the SQLite library +let existsTests = testList "Exists" [ + testList "byId" [ + testTask "succeeds when a document exists" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! exists = Exists.byId SqliteDb.TableName "three" + Expect.isTrue exists "There should have been an existing document" + } + testTask "succeeds when a document does not exist" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! exists = Exists.byId SqliteDb.TableName "seven" + Expect.isFalse exists "There should not have been an existing document" + } + ] + testList "byFields" [ + testTask "succeeds when documents exist" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! exists = Exists.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 10 ] + Expect.isTrue exists "There should have been existing documents" + } + testTask "succeeds when no matching documents exist" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! exists = Exists.byFields SqliteDb.TableName Any [ Field.LT "Nothing" "none" ] + Expect.isFalse exists "There should not have been any existing documents" + } + ] +] + +/// Integration tests for the Find module of the SQLite library +let findTests = testList "Find" [ + testList "all" [ + testTask "succeeds when there is data" { + use! db = SqliteDb.BuildDb() + + do! insert SqliteDb.TableName { Foo = "one"; Bar = "two" } + do! insert SqliteDb.TableName { Foo = "three"; Bar = "four" } + do! insert SqliteDb.TableName { Foo = "five"; Bar = "six" } + + let! results = Find.all SqliteDb.TableName + Expect.equal + results + [ { Foo = "one"; Bar = "two" }; { Foo = "three"; Bar = "four" }; { Foo = "five"; Bar = "six" } ] + "There should have been 3 documents returned" + } + testTask "succeeds when there is no data" { + use! db = SqliteDb.BuildDb() + let! results = Find.all SqliteDb.TableName + Expect.equal results [] "There should have been no documents returned" + } + ] + testList "byId" [ + testTask "succeeds when a document is found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = Find.byId SqliteDb.TableName "two" + Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.equal doc.Value.Id "two" "The incorrect document was returned" + } + testTask "succeeds when a document is not found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = Find.byId SqliteDb.TableName "three hundred eighty-seven" + Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + } + ] + testList "byFields" [ + testTask "succeeds when documents are found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = Find.byFields SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] + Expect.equal (List.length docs) 2 "There should have been two documents returned" + } + testTask "succeeds when documents are not found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! docs = Find.byFields SqliteDb.TableName Any [ Field.GT "NumValue" 100 ] + Expect.isTrue (List.isEmpty docs) "There should have been no documents returned" + } + ] + testList "firstByFields" [ + testTask "succeeds when a document is found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "another" ] + Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.equal doc.Value.Id "two" "The incorrect document was returned" + } + testTask "succeeds when multiple documents are found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Sub.Foo" "green" ] + Expect.isTrue (Option.isSome doc) "There should have been a document returned" + Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" + } + testTask "succeeds when a document is not found" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let! doc = Find.firstByFields SqliteDb.TableName Any [ Field.EQ "Value" "absent" ] + Expect.isFalse (Option.isSome doc) "There should not have been a document returned" + } + ] +] + +/// Integration tests for the Update module of the SQLite library +let updateTests = testList "Update" [ + testList "byId" [ + testTask "succeeds when a document is updated" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } } + do! Update.byId SqliteDb.TableName "one" testDoc + let! after = Find.byId SqliteDb.TableName "one" + Expect.isSome after "There should have been a document returned post-update" + Expect.equal after.Value testDoc "The updated document is not correct" + } + testTask "succeeds when no document is updated" { + use! db = SqliteDb.BuildDb() + + let! before = Find.all SqliteDb.TableName + Expect.isEmpty before "There should have been no documents returned" + + // This not raising an exception is the test + do! Update.byId + SqliteDb.TableName "test" { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } } + } + ] + testList "byFunc" [ + testTask "succeeds when a document is updated" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Update.byFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } + let! after = Find.byId SqliteDb.TableName "one" + Expect.isSome after "There should have been a document returned post-update" + Expect.equal + after.Value + { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } + "The updated document is not correct" + } + testTask "succeeds when no document is updated" { + use! db = SqliteDb.BuildDb() + + let! before = Find.all SqliteDb.TableName + Expect.isEmpty before "There should have been no documents returned" + + // This not raising an exception is the test + do! Update.byFunc SqliteDb.TableName (_.Id) { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } + } + ] +] + +/// Integration tests for the Patch module of the SQLite library +let patchTests = testList "Patch" [ + testList "byId" [ + testTask "succeeds when a document is updated" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Patch.byId SqliteDb.TableName "one" {| NumValue = 44 |} + let! after = Find.byId SqliteDb.TableName "one" + Expect.isSome after "There should have been a document returned post-update" + Expect.equal after.Value.NumValue 44 "The updated document is not correct" + } + testTask "succeeds when no document is updated" { + use! db = SqliteDb.BuildDb() + + let! before = Find.all SqliteDb.TableName + Expect.isEmpty before "There should have been no documents returned" + + // This not raising an exception is the test + do! Patch.byId SqliteDb.TableName "test" {| Foo = "green" |} + } + ] + testList "byFields" [ + testTask "succeeds when a document is updated" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "purple" ] {| NumValue = 77 |} + let! after = Count.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 77 ] + Expect.equal after 2L "There should have been 2 documents returned" + } + testTask "succeeds when no document is updated" { + use! db = SqliteDb.BuildDb() + + let! before = Find.all SqliteDb.TableName + Expect.isEmpty before "There should have been no documents returned" + + // This not raising an exception is the test + do! Patch.byFields SqliteDb.TableName Any [ Field.EQ "Value" "burgundy" ] {| Foo = "green" |} + } + ] +] + +/// Integration tests for the RemoveFields module of the SQLite library +let removeFieldsTests = testList "RemoveFields" [ + testList "byId" [ + testTask "succeeds when fields is removed" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byId SqliteDb.TableName "two" [ "Sub"; "Value" ] + try + let! _ = Find.byId SqliteDb.TableName "two" + Expect.isTrue false "The updated document should have failed to parse" + with + | :? JsonException -> () + | exn as ex -> Expect.isTrue false $"Threw {ex.GetType().Name} ({ex.Message})" + } + testTask "succeeds when a field is not removed" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byId SqliteDb.TableName "two" [ "AFieldThatIsNotThere" ] + } + testTask "succeeds when no document is matched" { + use! db = SqliteDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byId SqliteDb.TableName "two" [ "Value" ] + } + ] + testList "byFields" [ + testTask "succeeds when a field is removed" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Sub" ] + try + let! _ = Find.byId SqliteDb.TableName "four" + Expect.isTrue false "The updated document should have failed to parse" + with + | :? JsonException -> () + | exn as ex -> Expect.isTrue false $"Threw {ex.GetType().Name} ({ex.Message})" + } + testTask "succeeds when a field is not removed" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + // This not raising an exception is the test + do! RemoveFields.byFields SqliteDb.TableName Any [ Field.EQ "NumValue" 17 ] [ "Nothing" ] + } + testTask "succeeds when no document is matched" { + use! db = SqliteDb.BuildDb() + + // This not raising an exception is the test + do! RemoveFields.byFields SqliteDb.TableName Any [ Field.NE "Abracadabra" "apple" ] [ "Value" ] + } + ] +] + +/// Integration tests for the Delete module of the SQLite library +let deleteTests = testList "Delete" [ + testList "byId" [ + testTask "succeeds when a document is deleted" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Delete.byId SqliteDb.TableName "four" + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 4L "There should have been 4 documents remaining" + } + testTask "succeeds when a document is not deleted" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Delete.byId SqliteDb.TableName "thirty" + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 5L "There should have been 5 documents remaining" + } + ] + testList "byFields" [ + testTask "succeeds when documents are deleted" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Delete.byFields SqliteDb.TableName Any [ Field.NE "Value" "purple" ] + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 2L "There should have been 2 documents remaining" + } + testTask "succeeds when documents are not deleted" { + use! db = SqliteDb.BuildDb() + do! loadDocs () + + do! Delete.byFields SqliteDb.TableName Any [ Field.EQ "Value" "crimson" ] + let! remaining = Count.all SqliteDb.TableName + Expect.equal remaining 5L "There should have been 5 documents remaining" + } + ] +] + +/// All tests for the SQLite library +let all = testList "Sqlite" [ + testList "Unit" [ queryTests; parametersTests ] + testSequenced <| testList "Integration" [ + configurationTests + customTests + definitionTests + documentTests + countTests + existsTests + findTests + updateTests + patchTests + removeFieldsTests + deleteTests + test "clean up database" { Configuration.useConnectionString "data source=:memory:" } + ] +]