Add AutoId DU / tests

This commit is contained in:
Daniel J. Summers 2024-08-18 17:23:09 -04:00
parent 88f11a854f
commit b357b5a01f
4 changed files with 495 additions and 335 deletions

View File

@ -1,5 +1,7 @@
namespace BitBadger.Documents namespace BitBadger.Documents
open System.Security.Cryptography
/// The types of logical operations available for JSON fields /// The types of logical operations available for JSON fields
[<Struct>] [<Struct>]
type Op = type Op =
@ -148,6 +150,36 @@ type ParameterName() =
currentIdx <- currentIdx + 1 currentIdx <- currentIdx + 1
$"@field{currentIdx}" $"@field{currentIdx}"
#if NET6_0
open System.Text
#endif
/// Automatically-generated document ID options
[<Struct>]
type AutoId =
/// No automatic IDs will be generated
| Disabled
/// Generate a MAX-plus-1 numeric value for documents
| Number
/// Generate a GUID for each document (as a lowercase, no-dashes, 32-character string)
| Guid
/// Generate a random string of hexadecimal characters for each document
| RandomString
with
/// Generate a GUID string
static member GenerateGuid() =
System.Guid.NewGuid().ToString "N"
/// Generate a string of random hexadecimal characters
static member GenerateRandomString(length: int) =
#if NET8_0_OR_GREATER
RandomNumberGenerator.GetHexString(length, lowercase = true)
#else
RandomNumberGenerator.GetBytes((length / 2) + 1)
|> Array.fold (fun (str: StringBuilder) byt -> str.Append(byt.ToString "x2")) (StringBuilder length)
|> function it -> it.Length <- length; it.ToString()
#endif
/// The required document serialization implementation /// The required document serialization implementation
type IDocumentSerializer = type IDocumentSerializer =
@ -200,7 +232,7 @@ module Configuration =
serializerValue serializerValue
/// The serialized name of the ID field for documents /// The serialized name of the ID field for documents
let mutable idFieldValue = "Id" let mutable private idFieldValue = "Id"
/// Specify the name of the ID field for documents /// Specify the name of the ID field for documents
[<CompiledName "UseIdField">] [<CompiledName "UseIdField">]
@ -212,6 +244,32 @@ module Configuration =
let idField () = let idField () =
idFieldValue idFieldValue
/// The automatic ID strategy used by the library
let mutable private autoIdValue = Disabled
/// Specify the automatic ID generation strategy used by the library
[<CompiledName "UseAutoIdStrategy">]
let useAutoIdStrategy it =
autoIdValue <- it
/// Retrieve the currently configured automatic ID generation strategy
[<CompiledName "AutoIdStrategy">]
let autoIdStrategy () =
autoIdValue
/// The length of automatically generated random strings
let mutable private idStringLengthValue = 16
/// Specify the length of automatically generated random strings
[<CompiledName "UseIdStringLength">]
let useIdStringLength length =
idStringLengthValue <- length
/// Retrieve the currently configured length of automatically generated random strings
[<CompiledName "IdStringLength">]
let idStringLength () =
idStringLengthValue
/// Query construction functions /// Query construction functions
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]

View File

@ -70,6 +70,34 @@ public static class CommonCSharpTests
{ {
Configuration.UseIdField("Id"); Configuration.UseIdField("Id");
} }
}),
TestCase("UseAutoIdStrategy / AutoIdStrategy succeeds", () =>
{
try
{
Expect.equal(Configuration.AutoIdStrategy(), AutoId.Disabled,
"The default auto-ID strategy was incorrect");
Configuration.UseAutoIdStrategy(AutoId.Guid);
Expect.equal(Configuration.AutoIdStrategy(), AutoId.Guid,
"The auto-ID strategy was not set correctly");
}
finally
{
Configuration.UseAutoIdStrategy(AutoId.Disabled);
}
}),
TestCase("UseIdStringLength / IdStringLength succeeds", () =>
{
try
{
Expect.equal(Configuration.IdStringLength(), 16, "The default ID string length was incorrect");
Configuration.UseIdStringLength(33);
Expect.equal(Configuration.IdStringLength(), 33, "The ID string length was not set correctly");
}
finally
{
Configuration.UseIdStringLength(16);
}
}) })
])), ])),
TestList("Op", TestList("Op",
@ -295,6 +323,27 @@ public static class CommonCSharpTests
"Counter should have advanced from previous call"); "Counter should have advanced from previous call");
}) })
]), ]),
TestList("AutoId",
[
TestCase("GenerateGuid succeeds", () =>
{
var autoId = AutoId.GenerateGuid();
Expect.isNotNull(autoId, "The GUID auto-ID should not have been null");
Expect.stringHasLength(autoId, 32, "The GUID auto-ID should have been 32 characters long");
Expect.equal(autoId, autoId.ToLowerInvariant(), "The GUID auto-ID should have been lowercase");
}),
TestCase("GenerateRandomString succeeds", () =>
{
foreach (var length in (int[])[6, 8, 12, 20, 32, 57, 64])
{
var autoId = AutoId.GenerateRandomString(length);
Expect.isNotNull(autoId, $"Random string ({length}) should not have been null");
Expect.stringHasLength(autoId, length, $"Random string should have been {length} characters long");
Expect.equal(autoId, autoId.ToLowerInvariant(),
$"Random string ({length}) should have been lowercase");
}
})
]),
TestList("Query", TestList("Query",
[ [
TestCase("StatementWhere succeeds", () => TestCase("StatementWhere succeeds", () =>

View File

@ -6,10 +6,8 @@ open Expecto
/// Test table name /// Test table name
let tbl = "test_table" let tbl = "test_table"
/// Tests which do not hit the database /// Unit tests for the Op DU
let all = let opTests = testList "Op" [
testList "Common" [
testList "Op" [
test "EQ succeeds" { test "EQ succeeds" {
Expect.equal (string EQ) "=" "The equals operator was not correct" Expect.equal (string EQ) "=" "The equals operator was not correct"
} }
@ -37,8 +35,10 @@ let all =
test "NEX succeeds" { test "NEX succeeds" {
Expect.equal (string NEX) "IS NULL" """The "not exists" operator was not correct""" Expect.equal (string NEX) "IS NULL" """The "not exists" operator was not correct"""
} }
] ]
testList "Field" [
/// Unit tests for the Field class
let fieldTests = testList "Field" [
test "EQ succeeds" { test "EQ succeeds" {
let field = Field.EQ "Test" 14 let field = Field.EQ "Test" 14
Expect.equal field.Name "Test" "Field name incorrect" Expect.equal field.Name "Test" "Field name incorrect"
@ -111,12 +111,10 @@ let all =
} }
testList "NameToPath" [ testList "NameToPath" [
test "succeeds for PostgreSQL and a simple name" { test "succeeds for PostgreSQL and a simple name" {
Expect.equal Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" PostgreSQL) "Path not constructed correctly"
"data->>'Simple'" (Field.NameToPath "Simple" PostgreSQL) "Path not constructed correctly"
} }
test "succeeds for SQLite and a simple name" { test "succeeds for SQLite and a simple name" {
Expect.equal Expect.equal "data->>'Simple'" (Field.NameToPath "Simple" SQLite) "Path not constructed correctly"
"data->>'Simple'" (Field.NameToPath "Simple" SQLite) "Path not constructed correctly"
} }
test "succeeds for PostgreSQL and a nested name" { test "succeeds for PostgreSQL and a nested name" {
Expect.equal Expect.equal
@ -148,8 +146,7 @@ let all =
} }
test "succeeds for a PostgreSQL single field with a qualifier" { test "succeeds for a PostgreSQL single field with a qualifier" {
let field = { Field.LT "SomethingElse" 9 with Qualifier = Some "this" } let field = { Field.LT "SomethingElse" 9 with Qualifier = Some "this" }
Expect.equal Expect.equal "this.data->>'SomethingElse'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect"
"this.data->>'SomethingElse'" (field.Path PostgreSQL) "The PostgreSQL path is incorrect"
} }
test "succeeds for a PostgreSQL nested field with no qualifier" { test "succeeds for a PostgreSQL nested field with no qualifier" {
let field = Field.EQ "My.Nested.Field" "howdy" let field = Field.EQ "My.Nested.Field" "howdy"
@ -176,16 +173,20 @@ let all =
Expect.equal "bird.data->>'Nest'->>'Away'" (field.Path SQLite) "The SQLite path is incorrect" Expect.equal "bird.data->>'Nest'->>'Away'" (field.Path SQLite) "The SQLite path is incorrect"
} }
] ]
] ]
testList "FieldMatch.ToString" [
/// Unit tests for the FieldMatch DU
let fieldMatchTests = testList "FieldMatch.ToString" [
test "succeeds for Any" { test "succeeds for Any" {
Expect.equal (string Any) "OR" "SQL for Any is incorrect" Expect.equal (string Any) "OR" "SQL for Any is incorrect"
} }
test "succeeds for All" { test "succeeds for All" {
Expect.equal (string All) "AND" "SQL for All is incorrect" Expect.equal (string All) "AND" "SQL for All is incorrect"
} }
] ]
testList "ParameterName.Derive" [
/// Unit tests for the ParameterName class
let parameterNameTests = testList "ParameterName.Derive" [
test "succeeds with existing name" { test "succeeds with existing name" {
let name = ParameterName() let name = ParameterName()
Expect.equal (name.Derive(Some "@taco")) "@taco" "Name should have been @taco" Expect.equal (name.Derive(Some "@taco")) "@taco" "Name should have been @taco"
@ -198,8 +199,28 @@ let all =
Expect.equal (name.Derive None) "@field2" "Counter should have advanced from previous call" Expect.equal (name.Derive None) "@field2" "Counter should have advanced from previous call"
Expect.equal (name.Derive None) "@field3" "Counter should have advanced from previous call" Expect.equal (name.Derive None) "@field3" "Counter should have advanced from previous call"
} }
] ]
testList "Query" [
/// Unit tests for the AutoId DU
let autoIdTests = testList "AutoId" [
test "GenerateGuid succeeds" {
let autoId = AutoId.GenerateGuid()
Expect.isNotNull autoId "The GUID auto-ID should not have been null"
Expect.stringHasLength autoId 32 "The GUID auto-ID should have been 32 characters long"
Expect.equal autoId (autoId.ToLowerInvariant ()) "The GUID auto-ID should have been lowercase"
}
test "GenerateRandomString succeeds" {
[ 6; 8; 12; 20; 32; 57; 64 ]
|> List.iter (fun length ->
let autoId = AutoId.GenerateRandomString length
Expect.isNotNull autoId $"Random string ({length}) should not have been null"
Expect.stringHasLength autoId length $"Random string should have been {length} characters long"
Expect.equal autoId (autoId.ToLowerInvariant ()) $"Random string ({length}) should have been lowercase")
}
]
/// Unit tests for the Query module
let queryTests = testList "Query" [
test "statementWhere succeeds" { test "statementWhere succeeds" {
Expect.equal (Query.statementWhere "x" "y") "x WHERE y" "Statements not combined correctly" Expect.equal (Query.statementWhere "x" "y") "x WHERE y" "Statements not combined correctly"
} }
@ -321,5 +342,63 @@ let all =
"Order By not constructed correctly for numeric field" "Order By not constructed correctly for numeric field"
} }
] ]
] ]
]
/// Unit tests for the Configuration module
let configurationTests = testList "Configuration" [
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<obj> """{"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" {
try
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"
finally
Configuration.useIdField "Id"
}
test "useAutoIdStrategy / autoIdStrategy succeeds" {
try
Expect.equal (Configuration.autoIdStrategy ()) Disabled "The default auto-ID strategy was incorrect"
Configuration.useAutoIdStrategy Guid
Expect.equal (Configuration.autoIdStrategy ()) Guid "The auto-ID strategy was not set correctly"
finally
Configuration.useAutoIdStrategy Disabled
}
test "useIdStringLength / idStringLength succeeds" {
try
Expect.equal (Configuration.idStringLength ()) 16 "The default ID string length was incorrect"
Configuration.useIdStringLength 33
Expect.equal (Configuration.idStringLength ()) 33 "The ID string length was not set correctly"
finally
Configuration.useIdStringLength 16
}
]
/// Tests which do not hit the database
let all = testList "Common" [
opTests
fieldTests
fieldMatchTests
parameterNameTests
autoIdTests
queryTests
testSequenced configurationTests
]

View File

@ -144,32 +144,6 @@ let configurationTests = testList "Configuration" [
finally finally
Configuration.useConnectionString "Data Source=:memory:" 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<obj> """{"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 /// Integration tests for the Custom module of the SQLite library