Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
29 changed files with 1455 additions and 40 deletions
Showing only changes of commit a940e9c7f0 - Show all commits

View File

@ -3,6 +3,7 @@
<component name="AdditionalModuleElements"> <component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true"> <content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src/integration-test/kotlin" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/integration-test/kotlin" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
</content> </content>
</component> </component>
</module> </module>

10
pom.xml
View File

@ -38,7 +38,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style> <kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> <kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
<kotlin.version>2.1.0</kotlin.version> <kotlin.version>2.1.0</kotlin.version>
<serialization.version>1.8.0</serialization.version> <serialization.version>1.8.0</serialization.version>
</properties> </properties>
@ -111,6 +111,14 @@
<mainClass>MainKt</mainClass> <mainClass>MainKt</mainClass>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,6 +1,8 @@
package solutions.bitbadger.documents package solutions.bitbadger.documents
import kotlin.jvm.Throws
import kotlin.reflect.full.* import kotlin.reflect.full.*
import kotlin.reflect.jvm.isAccessible
/** /**
* Strategies for automatic document IDs * Strategies for automatic document IDs
@ -22,7 +24,7 @@ enum class AutoId {
* *
* @return A `UUID` string * @return A `UUID` string
*/ */
fun generateUUID(): String = @JvmStatic fun generateUUID(): String =
java.util.UUID.randomUUID().toString().replace("-", "") java.util.UUID.randomUUID().toString().replace("-", "")
/** /**
@ -31,7 +33,7 @@ enum class AutoId {
* @param length The length of the string (optional; defaults to configured length) * @param length The length of the string (optional; defaults to configured length)
* @return A string of random hex characters of the requested length * @return A string of random hex characters of the requested length
*/ */
fun generateRandomString(length: Int? = null): String = @JvmStatic fun generateRandomString(length: Int? = null): String =
(length ?: Configuration.idStringLength).let { len -> (length ?: Configuration.idStringLength).let { len ->
kotlin.random.Random.nextBytes((len + 2) / 2) kotlin.random.Random.nextBytes((len + 2) / 2)
.joinToString("") { String.format("%02x", it) } .joinToString("") { String.format("%02x", it) }
@ -47,12 +49,13 @@ enum class AutoId {
* @return `true` if the document needs an automatic ID, `false` if not * @return `true` if the document needs an automatic ID, `false` if not
* @throws DocumentException If bad input prevents the determination * @throws DocumentException If bad input prevents the determination
*/ */
fun <T> needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean { @Throws(DocumentException::class)
@JvmStatic fun <T> needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean {
if (document == null) throw DocumentException("document cannot be null") if (document == null) throw DocumentException("document cannot be null")
if (strategy == DISABLED) return false; if (strategy == DISABLED) return false
val id = document!!::class.memberProperties.find { it.name == idProp } val id = document!!::class.memberProperties.find { it.name == idProp }?.apply { isAccessible = true }
if (id == null) throw DocumentException("$idProp not found in document") if (id == null) throw DocumentException("$idProp not found in document")
if (strategy == NUMBER) { if (strategy == NUMBER) {
@ -65,11 +68,12 @@ enum class AutoId {
} }
} }
if (id.returnType == String::class.createType()) { val typ = id.returnType.toString()
if (typ.endsWith("String") || typ.endsWith("String!")) {
return id.call(document) == "" return id.call(document) == ""
} }
throw DocumentException("$idProp was not a string; cannot auto-generate UUID or random string") throw DocumentException("$idProp was not a string ($typ); cannot auto-generate UUID or random string")
} }
} }
} }

View File

@ -3,6 +3,7 @@ package solutions.bitbadger.documents
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.sql.Connection import java.sql.Connection
import java.sql.DriverManager import java.sql.DriverManager
import kotlin.jvm.Throws
object Configuration { object Configuration {
@ -12,25 +13,33 @@ object Configuration {
* The default sets `encodeDefaults` to `true` and `explicitNulls` to `false`; see * The default sets `encodeDefaults` to `true` and `explicitNulls` to `false`; see
* https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md for all configuration options * https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md for all configuration options
*/ */
@JvmField
var json = Json { var json = Json {
encodeDefaults = true encodeDefaults = true
explicitNulls = false explicitNulls = false
coerceInputValues = true coerceInputValues = true
} }
/** The field in which a document's ID is stored */ /** The field in which a document's ID is stored */
@JvmField
var idField = "id" var idField = "id"
/** The automatic ID strategy to use */ /** The automatic ID strategy to use */
@JvmField
var autoIdStrategy = AutoId.DISABLED var autoIdStrategy = AutoId.DISABLED
/** The length of automatic random hex character string */ /** The length of automatic random hex character string */
@JvmField
var idStringLength = 16 var idStringLength = 16
/** The JSON serializer to use for documents */
var serializer: DocumentSerializer = DocumentSerializerKotlin()
/** The derived dialect value from the connection string */ /** The derived dialect value from the connection string */
internal var dialectValue: Dialect? = null internal var dialectValue: Dialect? = null
/** The connection string for the JDBC connection */ /** The connection string for the JDBC connection */
@JvmStatic
var connectionString: String? = null var connectionString: String? = null
set(value) { set(value) {
field = value field = value
@ -43,6 +52,7 @@ object Configuration {
* @return A new connection to the configured database * @return A new connection to the configured database
* @throws IllegalArgumentException If the connection string is not set before calling this * @throws IllegalArgumentException If the connection string is not set before calling this
*/ */
@JvmStatic
fun dbConn(): Connection { fun dbConn(): Connection {
if (connectionString == null) { if (connectionString == null) {
throw IllegalArgumentException("Please provide a connection string before attempting data access") throw IllegalArgumentException("Please provide a connection string before attempting data access")
@ -57,7 +67,11 @@ object Configuration {
* @return The dialect for the current connection * @return The dialect for the current connection
* @throws DocumentException If the dialect has not been set * @throws DocumentException If the dialect has not been set
*/ */
@Throws(DocumentException::class)
@JvmStatic
@JvmOverloads
fun dialect(process: String? = null): Dialect = fun dialect(process: String? = null): Dialect =
dialectValue ?: throw DocumentException( dialectValue ?: throw DocumentException(
"Database mode not set" + if (process == null) "" else "; cannot $process") "Database mode not set" + if (process == null) "" else "; cannot $process"
)
} }

View File

@ -69,18 +69,18 @@ class Field<T> private constructor(
if (parameterName == null && !listOf(Op.EXISTS, Op.NOT_EXISTS).contains(comparison.op)) if (parameterName == null && !listOf(Op.EXISTS, Op.NOT_EXISTS).contains(comparison.op))
throw DocumentException("Parameter for $name must be specified") throw DocumentException("Parameter for $name must be specified")
val dialect = Configuration.dialect("make field WHERE clause") val dialect = Configuration.dialect("make field WHERE clause")
val fieldName = path(dialect, if (comparison.op == Op.IN_ARRAY) FieldFormat.JSON else FieldFormat.SQL) val fieldName = path(dialect, if (comparison.op == Op.IN_ARRAY) FieldFormat.JSON else FieldFormat.SQL)
val fieldPath = when (dialect) { val fieldPath = when (dialect) {
Dialect.POSTGRESQL -> if (comparison.isNumeric) "($fieldName)::numeric" else fieldName Dialect.POSTGRESQL -> if (comparison.isNumeric) "($fieldName)::numeric" else fieldName
Dialect.SQLITE -> fieldName Dialect.SQLITE -> fieldName
} }
val criteria = when (comparison.op) { val criteria = when (comparison.op) {
in listOf(Op.EXISTS, Op.NOT_EXISTS) -> "" in listOf(Op.EXISTS, Op.NOT_EXISTS) -> ""
Op.BETWEEN -> " ${parameterName}min AND ${parameterName}max" Op.BETWEEN -> " ${parameterName}min AND ${parameterName}max"
Op.IN -> " ($inParameterNames)" Op.IN -> " ($inParameterNames)"
Op.IN_ARRAY -> if (dialect == Dialect.POSTGRESQL) " ARRAY[$inParameterNames]" else "" Op.IN_ARRAY -> if (dialect == Dialect.POSTGRESQL) " ARRAY[$inParameterNames]" else ""
else -> " $parameterName" else -> " $parameterName"
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -134,7 +134,7 @@ class Field<T> private constructor(
} }
override fun toString() = override fun toString() =
"Field ${parameterName ?: "<unnamed>"} $comparison${qualifier?.let { " (qualifier $it)"} ?: ""}" "Field ${parameterName ?: "<unnamed>"} $comparison${qualifier?.let { " (qualifier $it)" } ?: ""}"
companion object { companion object {
@ -146,6 +146,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> equal(name: String, value: T, paramName: String? = null) = fun <T> equal(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.EQUAL, value), paramName) Field(name, ComparisonSingle(Op.EQUAL, value), paramName)
@ -157,6 +159,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> greater(name: String, value: T, paramName: String? = null) = fun <T> greater(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.GREATER, value), paramName) Field(name, ComparisonSingle(Op.GREATER, value), paramName)
@ -168,6 +172,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> greaterOrEqual(name: String, value: T, paramName: String? = null) = fun <T> greaterOrEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.GREATER_OR_EQUAL, value), paramName) Field(name, ComparisonSingle(Op.GREATER_OR_EQUAL, value), paramName)
@ -179,6 +185,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> less(name: String, value: T, paramName: String? = null) = fun <T> less(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.LESS, value), paramName) Field(name, ComparisonSingle(Op.LESS, value), paramName)
@ -190,6 +198,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> lessOrEqual(name: String, value: T, paramName: String? = null) = fun <T> lessOrEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.LESS_OR_EQUAL, value), paramName) Field(name, ComparisonSingle(Op.LESS_OR_EQUAL, value), paramName)
@ -201,6 +211,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> notEqual(name: String, value: T, paramName: String? = null) = fun <T> notEqual(name: String, value: T, paramName: String? = null) =
Field(name, ComparisonSingle(Op.NOT_EQUAL, value), paramName) Field(name, ComparisonSingle(Op.NOT_EQUAL, value), paramName)
@ -213,6 +225,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> between(name: String, minValue: T, maxValue: T, paramName: String? = null) = fun <T> between(name: String, minValue: T, maxValue: T, paramName: String? = null) =
Field(name, ComparisonBetween(Pair(minValue, maxValue)), paramName) Field(name, ComparisonBetween(Pair(minValue, maxValue)), paramName)
@ -224,6 +238,8 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> any(name: String, values: Collection<T>, paramName: String? = null) = fun <T> any(name: String, values: Collection<T>, paramName: String? = null) =
Field(name, ComparisonIn(values), paramName) Field(name, ComparisonIn(values), paramName)
@ -236,18 +252,50 @@ class Field<T> private constructor(
* @param paramName The parameter name for the field (optional, defaults to auto-generated) * @param paramName The parameter name for the field (optional, defaults to auto-generated)
* @return A `Field` with the given comparison * @return A `Field` with the given comparison
*/ */
@JvmStatic
@JvmOverloads
fun <T> inArray(name: String, tableName: String, values: Collection<T>, paramName: String? = null) = fun <T> inArray(name: String, tableName: String, values: Collection<T>, paramName: String? = null) =
Field(name, ComparisonInArray(Pair(tableName, values)), paramName) Field(name, ComparisonInArray(Pair(tableName, values)), paramName)
/**
* Create a field where a document field should exist
*
* @param name The name of the field whose existence should be checked
* @return A `Field` with the given comparison
*/
@JvmStatic
fun exists(name: String) = fun exists(name: String) =
Field(name, ComparisonSingle(Op.EXISTS, "")) Field(name, ComparisonSingle(Op.EXISTS, ""))
/**
* Create a field where a document field should not exist
*
* @param name The name of the field whose existence should be checked
* @return A `Field` with the given comparison
*/
@JvmStatic
fun notExists(name: String) = fun notExists(name: String) =
Field(name, ComparisonSingle(Op.NOT_EXISTS, "")) Field(name, ComparisonSingle(Op.NOT_EXISTS, ""))
/**
* Create a field with a given named comparison (useful for ordering fields)
*
* @param name The name of the field
* @return A `Field` with the given name (comparison equal to an empty string)
*/
@JvmStatic
fun named(name: String) = fun named(name: String) =
Field(name, ComparisonSingle(Op.EQUAL, "")) Field(name, ComparisonSingle(Op.EQUAL, ""))
/**
* Convert a name to the SQL path for the given dialect
*
* @param name The field name to be translated
* @param dialect The database for which the path should be created
* @param format Whether the field should be retrieved as a JSON value or a SQL value
* @return The path to the JSON field
*/
@JvmStatic
fun nameToPath(name: String, dialect: Dialect, format: FieldFormat): String { fun nameToPath(name: String, dialect: Dialect, format: FieldFormat): String {
val path = StringBuilder("data") val path = StringBuilder("data")
val extra = if (format == FieldFormat.SQL) ">" else "" val extra = if (format == FieldFormat.SQL) ">" else ""

View File

@ -3,6 +3,7 @@ package solutions.bitbadger.documents
import java.sql.Connection import java.sql.Connection
import java.sql.PreparedStatement import java.sql.PreparedStatement
import java.sql.SQLException import java.sql.SQLException
import kotlin.jvm.Throws
/** /**
* Functions to assist with the creation and implementation of parameters for SQL queries * Functions to assist with the creation and implementation of parameters for SQL queries
@ -17,6 +18,7 @@ object Parameters {
* @param fields The collection of fields to be named * @param fields The collection of fields to be named
* @return The collection of fields with parameter names assigned * @return The collection of fields with parameter names assigned
*/ */
@JvmStatic
fun nameFields(fields: Collection<Field<*>>): Collection<Field<*>> { fun nameFields(fields: Collection<Field<*>>): Collection<Field<*>> {
val name = ParameterName() val name = ParameterName()
return fields.map { return fields.map {
@ -45,6 +47,7 @@ object Parameters {
* @param existing Any existing parameters for the query (optional, defaults to empty collection) * @param existing Any existing parameters for the query (optional, defaults to empty collection)
* @return A collection of parameters for the query * @return A collection of parameters for the query
*/ */
@JvmStatic
fun addFields(fields: Collection<Field<*>>, existing: MutableCollection<Parameter<*>> = mutableListOf()) = fun addFields(fields: Collection<Field<*>>, existing: MutableCollection<Parameter<*>> = mutableListOf()) =
fields.fold(existing) { acc, field -> field.appendParameter(acc) } fields.fold(existing) { acc, field -> field.appendParameter(acc) }
@ -55,6 +58,7 @@ object Parameters {
* @param parameters The parameters for the query * @param parameters The parameters for the query
* @return The query, with name parameters changed to `?`s * @return The query, with name parameters changed to `?`s
*/ */
@JvmStatic
fun replaceNamesInQuery(query: String, parameters: Collection<Parameter<*>>) = fun replaceNamesInQuery(query: String, parameters: Collection<Parameter<*>>) =
parameters.sortedByDescending { it.name.length }.fold(query) { acc, param -> acc.replace(param.name, "?") } parameters.sortedByDescending { it.name.length }.fold(query) { acc, param -> acc.replace(param.name, "?") }
@ -67,6 +71,8 @@ object Parameters {
* @return A `PreparedStatement` with the parameter names replaced with `?` and parameter values bound * @return A `PreparedStatement` with the parameter names replaced with `?` and parameter values bound
* @throws DocumentException If parameter names are invalid or number value types are invalid * @throws DocumentException If parameter names are invalid or number value types are invalid
*/ */
@Throws(DocumentException::class)
@JvmStatic
fun apply(conn: Connection, query: String, parameters: Collection<Parameter<*>>): PreparedStatement { fun apply(conn: Connection, query: String, parameters: Collection<Parameter<*>>): PreparedStatement {
if (parameters.isEmpty()) return try { if (parameters.isEmpty()) return try {
@ -105,6 +111,8 @@ object Parameters {
* @param parameterName The parameter name to use for the query * @param parameterName The parameter name to use for the query
* @return A list of parameters to use for building the query * @return A list of parameters to use for building the query
*/ */
@JvmStatic
@JvmOverloads
fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> = fun fieldNames(names: Collection<String>, parameterName: String = ":name"): MutableCollection<Parameter<*>> =
when (Configuration.dialect("generate field name parameters")) { when (Configuration.dialect("generate field name parameters")) {
Dialect.POSTGRESQL -> mutableListOf( Dialect.POSTGRESQL -> mutableListOf(

View File

@ -0,0 +1,217 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.AutoId;
import solutions.bitbadger.documents.DocumentException;
import solutions.bitbadger.documents.java.testDocs.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `AutoId` enum
*/
@DisplayName("Java | AutoId")
final public class AutoIdTest {
@Test
@DisplayName("Generates a UUID string")
public void generateUUID() {
assertEquals(32, AutoId.generateUUID().length(), "The UUID should have been a 32-character string");
}
@Test
@DisplayName("Generates a random hex character string of an even length")
public void generateRandomStringEven() {
final String result = AutoId.generateRandomString(8);
assertEquals(8, result.length(), "There should have been 8 characters in " + result);
}
@Test
@DisplayName("Generates a random hex character string of an odd length")
public void generateRandomStringOdd() {
final String result = AutoId.generateRandomString(11);
assertEquals(11, result.length(), "There should have been 11 characters in " + result);
}
@Test
@DisplayName("Generates different random hex character strings")
public void generateRandomStringIsRandom() {
final String result1 = AutoId.generateRandomString(16);
final String result2 = AutoId.generateRandomString(16);
assertNotEquals(result1, result2, "There should have been 2 different strings generated");
}
@Test
@DisplayName("needsAutoId fails for null document")
public void needsAutoIdFailsForNullDocument() {
assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.DISABLED, null, "id"));
}
@Test
@DisplayName("needsAutoId fails for missing ID property")
public void needsAutoIdFailsForMissingId() {
assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.UUID, new IntIdClass(0), "Id"));
}
@Test
@DisplayName("needsAutoId returns false if disabled")
public void needsAutoIdFalseIfDisabled() {
try {
assertFalse(AutoId.needsAutoId(AutoId.DISABLED, "", ""), "Disabled Auto ID should always return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns true for Number strategy and byte ID of 0")
public void needsAutoIdTrueForByteWithZero() {
try {
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 0), "id"),
"Number Auto ID with 0 should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for Number strategy and byte ID of non-0")
public void needsAutoIdFalseForByteWithNonZero() {
try {
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ByteIdClass((byte) 77), "id"),
"Number Auto ID with 77 should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns true for Number strategy and short ID of 0")
public void needsAutoIdTrueForShortWithZero() {
try {
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 0), "id"),
"Number Auto ID with 0 should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for Number strategy and short ID of non-0")
public void needsAutoIdFalseForShortWithNonZero() {
try {
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new ShortIdClass((short) 31), "id"),
"Number Auto ID with 31 should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns true for Number strategy and int ID of 0")
public void needsAutoIdTrueForIntWithZero() {
try {
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(0), "id"),
"Number Auto ID with 0 should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for Number strategy and int ID of non-0")
public void needsAutoIdFalseForIntWithNonZero() {
try {
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new IntIdClass(6), "id"),
"Number Auto ID with 6 should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns true for Number strategy and long ID of 0")
public void needsAutoIdTrueForLongWithZero() {
try {
assertTrue(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(0L), "id"),
"Number Auto ID with 0 should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for Number strategy and long ID of non-0")
public void needsAutoIdFalseForLongWithNonZero() {
try {
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, new LongIdClass(2L), "id"),
"Number Auto ID with 2 should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId fails for Number strategy and non-number ID")
public void needsAutoIdFailsForNumberWithStringId() {
assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.NUMBER, new StringIdClass(""), "id"));
}
@Test
@DisplayName("needsAutoId returns true for UUID strategy and blank ID")
public void needsAutoIdTrueForUUIDWithBlank() {
try {
assertTrue(AutoId.needsAutoId(AutoId.UUID, new StringIdClass(""), "id"),
"UUID Auto ID with blank should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for UUID strategy and non-blank ID")
public void needsAutoIdFalseForUUIDNotBlank() {
try {
assertFalse(AutoId.needsAutoId(AutoId.UUID, new StringIdClass("howdy"), "id"),
"UUID Auto ID with non-blank should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId fails for UUID strategy and non-string ID")
public void needsAutoIdFailsForUUIDNonString() {
assertThrows(DocumentException.class, () -> AutoId.needsAutoId(AutoId.UUID, new IntIdClass(5), "id"));
}
@Test
@DisplayName("needsAutoId returns true for Random String strategy and blank ID")
public void needsAutoIdTrueForRandomWithBlank() {
try {
assertTrue(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass(""), "id"),
"Random String Auto ID with blank should return true");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId returns false for Random String strategy and non-blank ID")
public void needsAutoIdFalseForRandomNotBlank() {
try {
assertFalse(AutoId.needsAutoId(AutoId.RANDOM_STRING, new StringIdClass("full"), "id"),
"Random String Auto ID with non-blank should return false");
} catch (DocumentException ex) {
fail(ex);
}
}
@Test
@DisplayName("needsAutoId fails for Random String strategy and non-string ID")
public void needsAutoIdFailsForRandomNonString() {
assertThrows(DocumentException.class,
() -> AutoId.needsAutoId(AutoId.RANDOM_STRING, new ShortIdClass((short) 55), "id"));
}
}

View File

@ -0,0 +1,56 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Configuration` object
*/
@DisplayName("Java | Configuration")
final public class ConfigurationTest {
@Test
@DisplayName("Default JSON options are as expected")
public void defaultJsonOptions() {
assertTrue(Configuration.json.getConfiguration().getEncodeDefaults(), "Encode Defaults should have been set");
assertFalse(Configuration.json.getConfiguration().getExplicitNulls(),
"Explicit Nulls should not have been set");
assertTrue(Configuration.json.getConfiguration().getCoerceInputValues(),
"Coerce Input Values should have been set");
}
@Test
@DisplayName("Default ID field is `id`")
public void defaultIdField() {
assertEquals("id", Configuration.idField, "Default ID field incorrect");
}
@Test
@DisplayName("Default Auto ID strategy is `DISABLED`")
public void defaultAutoId() {
assertEquals(AutoId.DISABLED, Configuration.autoIdStrategy, "Default Auto ID strategy should be `disabled`");
}
@Test
@DisplayName("Default ID string length should be 16")
public void defaultIdStringLength() {
assertEquals(16, Configuration.idStringLength, "Default ID string length should be 16");
}
@Test
@DisplayName("Dialect is derived from connection string")
public void dialectIsDerived() {
try {
assertThrows(DocumentException.class, Configuration::dialect);
Configuration.setConnectionString("jdbc:postgresql:db");
assertEquals(Dialect.POSTGRESQL, Configuration.dialect());
} catch (DocumentException ex) {
fail(ex);
} finally {
Configuration.setConnectionString(null);
}
}
}

View File

@ -0,0 +1,26 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.DocumentIndex;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `DocumentIndex` enum
*/
@DisplayName("Java | DocumentIndex")
final public class DocumentIndexTest {
@Test
@DisplayName("FULL uses proper SQL")
public void fullSQL() {
assertEquals("", DocumentIndex.FULL.getSql(), "The SQL for Full is incorrect");
}
@Test
@DisplayName("OPTIMIZED uses proper SQL")
public void optimizedSQL() {
assertEquals(" jsonb_path_ops", DocumentIndex.OPTIMIZED.getSql(), "The SQL for Optimized is incorrect");
}
}

View File

@ -0,0 +1,26 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.FieldMatch;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `FieldMatch` enum
*/
@DisplayName("Java | FieldMatch")
final public class FieldMatchTest {
@Test
@DisplayName("ANY uses proper SQL")
public void any() {
assertEquals("OR", FieldMatch.ANY.getSql(), "ANY should use OR");
}
@Test
@DisplayName("ALL uses proper SQL")
public void all() {
assertEquals("AND", FieldMatch.ALL.getSql(), "ALL should use AND");
}
}

View File

@ -0,0 +1,629 @@
package solutions.bitbadger.documents.java;
import kotlin.Pair;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*;
import java.util.Collection;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Field` class
*/
@DisplayName("Java | Field")
final public class FieldTest {
/**
* Clear the connection string (resets Dialect)
*/
@AfterEach
public void cleanUp() {
Configuration.setConnectionString(null);
}
// ~~~ INSTANCE METHODS ~~~
@Test
@DisplayName("withParameterName fails for invalid name")
public void withParamNameFails() {
assertThrows(DocumentException.class, () -> Field.equal("it", "").withParameterName("2424"));
}
@Test
@DisplayName("withParameterName works with colon prefix")
public void withParamNameColon() {
Field<String> field = Field.equal("abc", "22").withQualifier("me");
Field<String> withParam = field.withParameterName(":test");
assertNotSame(field, withParam, "A new Field instance should have been created");
assertEquals(field.getName(), withParam.getName(), "Name should have been preserved");
assertEquals(field.getComparison(), withParam.getComparison(), "Comparison should have been preserved");
assertEquals(":test", withParam.getParameterName(), "Parameter name not set correctly");
assertEquals(field.getQualifier(), withParam.getQualifier(), "Qualifier should have been preserved");
}
@Test
@DisplayName("withParameterName works with at-sign prefix")
public void withParamNameAtSign() {
Field<String> field = Field.equal("def", "44");
Field<String> withParam = field.withParameterName("@unit");
assertNotSame(field, withParam, "A new Field instance should have been created");
assertEquals(field.getName(), withParam.getName(), "Name should have been preserved");
assertEquals(field.getComparison(), withParam.getComparison(), "Comparison should have been preserved");
assertEquals("@unit", withParam.getParameterName(), "Parameter name not set correctly");
assertEquals(field.getQualifier(), withParam.getQualifier(), "Qualifier should have been preserved");
}
@Test
@DisplayName("withQualifier sets qualifier correctly")
public void withQualifier() {
Field<String> field = Field.equal("j", "k");
Field<String> withQual = field.withQualifier("test");
assertNotSame(field, withQual, "A new Field instance should have been created");
assertEquals(field.getName(), withQual.getName(), "Name should have been preserved");
assertEquals(field.getComparison(), withQual.getComparison(), "Comparison should have been preserved");
assertEquals(field.getParameterName(), withQual.getParameterName(),
"Parameter Name should have been preserved");
assertEquals("test", withQual.getQualifier(), "Qualifier not set correctly");
}
@Test
@DisplayName("path generates for simple unqualified PostgreSQL field")
public void pathPostgresSimpleUnqualified() {
assertEquals("data->>'SomethingCool'",
Field.greaterOrEqual("SomethingCool", 18).path(Dialect.POSTGRESQL, FieldFormat.SQL),
"Path not correct");
}
@Test
@DisplayName("path generates for simple qualified PostgreSQL field")
public void pathPostgresSimpleQualified() {
assertEquals("this.data->>'SomethingElse'",
Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.POSTGRESQL, FieldFormat.SQL),
"Path not correct");
}
@Test
@DisplayName("path generates for nested unqualified PostgreSQL field")
public void pathPostgresNestedUnqualified() {
assertEquals("data#>>'{My,Nested,Field}'",
Field.equal("My.Nested.Field", "howdy").path(Dialect.POSTGRESQL, FieldFormat.SQL), "Path not correct");
}
@Test
@DisplayName("path generates for nested qualified PostgreSQL field")
public void pathPostgresNestedQualified() {
assertEquals("bird.data#>>'{Nest,Away}'",
Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.POSTGRESQL, FieldFormat.SQL),
"Path not correct");
}
@Test
@DisplayName("path generates for simple unqualified SQLite field")
public void pathSQLiteSimpleUnqualified() {
assertEquals("data->>'SomethingCool'",
Field.greaterOrEqual("SomethingCool", 18).path(Dialect.SQLITE, FieldFormat.SQL), "Path not correct");
}
@Test
@DisplayName("path generates for simple qualified SQLite field")
public void pathSQLiteSimpleQualified() {
assertEquals("this.data->>'SomethingElse'",
Field.less("SomethingElse", 9).withQualifier("this").path(Dialect.SQLITE, FieldFormat.SQL),
"Path not correct");
}
@Test
@DisplayName("path generates for nested unqualified SQLite field")
public void pathSQLiteNestedUnqualified() {
assertEquals("data->'My'->'Nested'->>'Field'",
Field.equal("My.Nested.Field", "howdy").path(Dialect.SQLITE, FieldFormat.SQL), "Path not correct");
}
@Test
@DisplayName("path generates for nested qualified SQLite field")
public void pathSQLiteNestedQualified() {
assertEquals("bird.data->'Nest'->>'Away'",
Field.equal("Nest.Away", "doc").withQualifier("bird").path(Dialect.SQLITE, FieldFormat.SQL),
"Path not correct");
}
@Test
@DisplayName("toWhere generates for exists w/o qualifier (PostgreSQL)")
public void toWhereExistsNoQualPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for exists w/o qualifier (SQLite)")
public void toWhereExistsNoQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("data->>'that_field' IS NOT NULL", Field.exists("that_field").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for not-exists w/o qualifier (PostgreSQL)")
public void toWhereNotExistsNoQualPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for not-exists w/o qualifier (SQLite)")
public void toWhereNotExistsNoQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("data->>'a_field' IS NULL", Field.notExists("a_field").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, numeric range (PostgreSQL)")
public void toWhereBetweenNoQualNumericPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").toWhere(), "Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier, alphanumeric range (PostgreSQL)")
public void toWhereBetweenNoQualAlphaPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/o qualifier (SQLite)")
public void toWhereBetweenNoQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field.between("age", 13, 17, "@age").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, numeric range (PostgreSQL)")
public void toWhereBetweenQualNumericPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("(test.data->>'age')::numeric BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier, alphanumeric range (PostgreSQL)")
public void toWhereBetweenQualAlphaPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("unit.data->>'city' BETWEEN :citymin AND :citymax",
Field.between("city", "Atlanta", "Chicago", ":city").withQualifier("unit").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for BETWEEN w/ qualifier (SQLite)")
public void toWhereBetweenQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("my.data->>'age' BETWEEN @agemin AND @agemax",
Field.between("age", 13, 17, "@age").withQualifier("my").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for IN/any, numeric values (PostgreSQL)")
public void toWhereAnyNumericPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("(data->>'even')::numeric IN (:nbr_0, :nbr_1, :nbr_2)",
Field.any("even", List.of(2, 4, 6), ":nbr").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for IN/any, alphanumeric values (PostgreSQL)")
public void toWhereAnyAlphaPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", List.of("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for IN/any (SQLite)")
public void toWhereAnySQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("data->>'test' IN (:city_0, :city_1)",
Field.any("test", List.of("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for inArray (PostgreSQL)")
public void toWhereInArrayPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]",
Field.inArray("even", "tbl", List.of(2, 4, 6, 8), ":it").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for inArray (SQLite)")
public void toWhereInArraySQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("EXISTS (SELECT 1 FROM json_each(tbl.data, '$.test') WHERE value IN (:city_0, :city_1))",
Field.inArray("test", "tbl", List.of("Atlanta", "Chicago"), ":city").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for others w/o qualifier (PostgreSQL)")
public void toWhereOtherNoQualPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates for others w/o qualifier (SQLite)")
public void toWhereOtherNoQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("data->>'some_field' = :value", Field.equal("some_field", "", ":value").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates no-parameter w/ qualifier (PostgreSQL)")
public void toWhereNoParamWithQualPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates no-parameter w/ qualifier (SQLite)")
public void toWhereNoParamWithQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("test.data->>'no_field' IS NOT NULL", Field.exists("no_field").withQualifier("test").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates parameter w/ qualifier (PostgreSQL)")
public void toWhereParamWithQualPostgres() {
Configuration.setConnectionString(":postgresql:");
assertEquals("(q.data->>'le_field')::numeric <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly");
}
@Test
@DisplayName("toWhere generates parameter w/ qualifier (SQLite)")
public void toWhereParamWithQualSQLite() {
Configuration.setConnectionString(":sqlite:");
assertEquals("q.data->>'le_field' <= :it",
Field.lessOrEqual("le_field", 18, ":it").withQualifier("q").toWhere(),
"Field WHERE clause not generated correctly");
}
// ~~~ STATIC TESTS ~~~
@Test
@DisplayName("equal constructs a field w/o parameter name")
public void equalCtor() {
Field<Integer> field = Field.equal("Test", 14);
assertEquals("Test", field.getName(), "Field name not filled correctly");
assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("equal constructs a field w/ parameter name")
public void equalParameterCtor() {
Field<Integer> field = Field.equal("Test", 14, ":w");
assertEquals("Test", field.getName(), "Field name not filled correctly");
assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(14, field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":w", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("greater constructs a field w/o parameter name")
public void greaterCtor() {
Field<String> field = Field.greater("Great", "night");
assertEquals("Great", field.getName(), "Field name not filled correctly");
assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("greater constructs a field w/ parameter name")
public void greaterParameterCtor() {
Field<String> field = Field.greater("Great", "night", ":yeah");
assertEquals("Great", field.getName(), "Field name not filled correctly");
assertEquals(Op.GREATER, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("night", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":yeah", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("greaterOrEqual constructs a field w/o parameter name")
public void greaterOrEqualCtor() {
Field<Long> field = Field.greaterOrEqual("Nice", 88L);
assertEquals("Nice", field.getName(), "Field name not filled correctly");
assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(),
"Field comparison operation not filled correctly");
assertEquals(88L, field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("greaterOrEqual constructs a field w/ parameter name")
public void greaterOrEqualParameterCtor() {
Field<Long> field = Field.greaterOrEqual("Nice", 88L, ":nice");
assertEquals("Nice", field.getName(), "Field name not filled correctly");
assertEquals(Op.GREATER_OR_EQUAL, field.getComparison().getOp(),
"Field comparison operation not filled correctly");
assertEquals(88L, field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":nice", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("less constructs a field w/o parameter name")
public void lessCtor() {
Field<String> field = Field.less("Lesser", "seven");
assertEquals("Lesser", field.getName(), "Field name not filled correctly");
assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("less constructs a field w/ parameter name")
public void lessParameterCtor() {
Field<String> field = Field.less("Lesser", "seven", ":max");
assertEquals("Lesser", field.getName(), "Field name not filled correctly");
assertEquals(Op.LESS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("seven", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":max", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("lessOrEqual constructs a field w/o parameter name")
public void lessOrEqualCtor() {
Field<String> field = Field.lessOrEqual("Nobody", "KNOWS");
assertEquals("Nobody", field.getName(), "Field name not filled correctly");
assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(),
"Field comparison operation not filled correctly");
assertEquals("KNOWS", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("lessOrEqual constructs a field w/ parameter name")
public void lessOrEqualParameterCtor() {
Field<String> field = Field.lessOrEqual("Nobody", "KNOWS", ":nope");
assertEquals("Nobody", field.getName(), "Field name not filled correctly");
assertEquals(Op.LESS_OR_EQUAL, field.getComparison().getOp(),
"Field comparison operation not filled correctly");
assertEquals("KNOWS", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":nope", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("notEqual constructs a field w/o parameter name")
public void notEqualCtor() {
Field<String> field = Field.notEqual("Park", "here");
assertEquals("Park", field.getName(), "Field name not filled correctly");
assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("notEqual constructs a field w/ parameter name")
public void notEqualParameterCtor() {
Field<String> field = Field.notEqual("Park", "here", ":now");
assertEquals("Park", field.getName(), "Field name not filled correctly");
assertEquals(Op.NOT_EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("here", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertEquals(":now", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("between constructs a field w/o parameter name")
public void betweenCtor() {
Field<Pair<Integer, Integer>> field = Field.between("Age", 18, 49);
assertEquals("Age", field.getName(), "Field name not filled correctly");
assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(18, field.getComparison().getValue().getFirst(),
"Field comparison min value not filled correctly");
assertEquals(49, field.getComparison().getValue().getSecond(),
"Field comparison max value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("between constructs a field w/ parameter name")
public void betweenParameterCtor() {
Field<Pair<Integer, Integer>> field = Field.between("Age", 18, 49, ":limit");
assertEquals("Age", field.getName(), "Field name not filled correctly");
assertEquals(Op.BETWEEN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(18, field.getComparison().getValue().getFirst(),
"Field comparison min value not filled correctly");
assertEquals(49, field.getComparison().getValue().getSecond(),
"Field comparison max value not filled correctly");
assertEquals(":limit", field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("any constructs a field w/o parameter name")
public void anyCtor() {
Field<Collection<Integer>> field = Field.any("Here", List.of(8, 16, 32));
assertEquals("Here", field.getName(), "Field name not filled correctly");
assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(List.of(8, 16, 32), field.getComparison().getValue(),
"Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("any constructs a field w/ parameter name")
public void anyParameterCtor() {
Field<Collection<Integer>> field = Field.any("Here", List.of(8, 16, 32), ":list");
assertEquals("Here", field.getName(), "Field name not filled correctly");
assertEquals(Op.IN, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals(List.of(8, 16, 32), field.getComparison().getValue(),
"Field comparison value not filled correctly");
assertEquals(":list", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("inArray constructs a field w/o parameter name")
public void inArrayCtor() {
Field<Pair<String, Collection<String>>> field = Field.inArray("ArrayField", "table", List.of("z"));
assertEquals("ArrayField", field.getName(), "Field name not filled correctly");
assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("table", field.getComparison().getValue().getFirst(),
"Field comparison table not filled correctly");
assertEquals(List.of("z"), field.getComparison().getValue().getSecond(),
"Field comparison values not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("inArray constructs a field w/ parameter name")
public void inArrayParameterCtor() {
Field<Pair<String, Collection<String>>> field = Field.inArray("ArrayField", "table", List.of("z"), ":a");
assertEquals("ArrayField", field.getName(), "Field name not filled correctly");
assertEquals(Op.IN_ARRAY, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("table", field.getComparison().getValue().getFirst(),
"Field comparison table not filled correctly");
assertEquals(List.of("z"), field.getComparison().getValue().getSecond(),
"Field comparison values not filled correctly");
assertEquals(":a", field.getParameterName(), "Field parameter name not filled correctly");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("exists constructs a field")
public void existsCtor() {
Field<String> field = Field.exists("Groovy");
assertEquals("Groovy", field.getName(), "Field name not filled correctly");
assertEquals(Op.EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("notExists constructs a field")
public void notExistsCtor() {
Field<String> field = Field.notExists("Groovy");
assertEquals("Groovy", field.getName(), "Field name not filled correctly");
assertEquals(Op.NOT_EXISTS, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("named constructs a field")
public void namedCtor() {
Field<String> field = Field.named("Tacos");
assertEquals("Tacos", field.getName(), "Field name not filled correctly");
assertEquals(Op.EQUAL, field.getComparison().getOp(), "Field comparison operation not filled correctly");
assertEquals("", field.getComparison().getValue(), "Field comparison value not filled correctly");
assertNull(field.getParameterName(), "The parameter name should have been null");
assertNull(field.getQualifier(), "The qualifier should have been null");
}
@Test
@DisplayName("static constructors fail for invalid parameter name")
public void staticCtorsFailOnParamName() {
assertThrows(DocumentException.class, () -> Field.equal("a", "b", "that ain't it, Jack..."));
}
@Test
@DisplayName("nameToPath creates a simple PostgreSQL SQL name")
public void nameToPathPostgresSimpleSQL() {
assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.SQL),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a simple SQLite SQL name")
public void nameToPathSQLiteSimpleSQL() {
assertEquals("data->>'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.SQL),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a nested PostgreSQL SQL name")
public void nameToPathPostgresNestedSQL() {
assertEquals("data#>>'{A,Long,Path,to,the,Property}'",
Field.nameToPath("A.Long.Path.to.the.Property", Dialect.POSTGRESQL, FieldFormat.SQL),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a nested SQLite SQL name")
public void nameToPathSQLiteNestedSQL() {
assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->>'Property'",
Field.nameToPath("A.Long.Path.to.the.Property", Dialect.SQLITE, FieldFormat.SQL),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a simple PostgreSQL JSON name")
public void nameToPathPostgresSimpleJSON() {
assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.POSTGRESQL, FieldFormat.JSON),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a simple SQLite JSON name")
public void nameToPathSQLiteSimpleJSON() {
assertEquals("data->'Simple'", Field.nameToPath("Simple", Dialect.SQLITE, FieldFormat.JSON),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a nested PostgreSQL JSON name")
public void nameToPathPostgresNestedJSON() {
assertEquals("data#>'{A,Long,Path,to,the,Property}'",
Field.nameToPath("A.Long.Path.to.the.Property", Dialect.POSTGRESQL, FieldFormat.JSON),
"Path not constructed correctly");
}
@Test
@DisplayName("nameToPath creates a nested SQLite JSON name")
public void nameToPathSQLiteNestedJSON() {
assertEquals("data->'A'->'Long'->'Path'->'to'->'the'->'Property'",
Field.nameToPath("A.Long.Path.to.the.Property", Dialect.SQLITE, FieldFormat.JSON),
"Path not constructed correctly");
}
}

View File

@ -0,0 +1,80 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.Op;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `Op` enum
*/
@DisplayName("Java | Op")
final public class OpTest {
@Test
@DisplayName("EQUAL uses proper SQL")
public void equalSQL() {
assertEquals("=", Op.EQUAL.getSql(), "The SQL for equal is incorrect");
}
@Test
@DisplayName("GREATER uses proper SQL")
public void greaterSQL() {
assertEquals(">", Op.GREATER.getSql(), "The SQL for greater is incorrect");
}
@Test
@DisplayName("GREATER_OR_EQUAL uses proper SQL")
public void greaterOrEqualSQL() {
assertEquals(">=", Op.GREATER_OR_EQUAL.getSql(), "The SQL for greater-or-equal is incorrect");
}
@Test
@DisplayName("LESS uses proper SQL")
public void lessSQL() {
assertEquals("<", Op.LESS.getSql(), "The SQL for less is incorrect");
}
@Test
@DisplayName("LESS_OR_EQUAL uses proper SQL")
public void lessOrEqualSQL() {
assertEquals("<=", Op.LESS_OR_EQUAL.getSql(), "The SQL for less-or-equal is incorrect");
}
@Test
@DisplayName("NOT_EQUAL uses proper SQL")
public void notEqualSQL() {
assertEquals("<>", Op.NOT_EQUAL.getSql(), "The SQL for not-equal is incorrect");
}
@Test
@DisplayName("BETWEEN uses proper SQL")
public void betweenSQL() {
assertEquals("BETWEEN", Op.BETWEEN.getSql(), "The SQL for between is incorrect");
}
@Test
@DisplayName("IN uses proper SQL")
public void inSQL() {
assertEquals("IN", Op.IN.getSql(), "The SQL for in is incorrect");
}
@Test
@DisplayName("IN_ARRAY uses proper SQL")
public void inArraySQL() {
assertEquals("??|", Op.IN_ARRAY.getSql(), "The SQL for in-array is incorrect");
}
@Test
@DisplayName("EXISTS uses proper SQL")
public void existsSQL() {
assertEquals("IS NOT NULL", Op.EXISTS.getSql(), "The SQL for exists is incorrect");
}
@Test
@DisplayName("NOT_EXISTS uses proper SQL")
public void notExistsSQL() {
assertEquals("IS NULL", Op.NOT_EXISTS.getSql(), "The SQL for not-exists is incorrect");
}
}

View File

@ -0,0 +1,32 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.ParameterName;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for the `ParameterName` class
*/
@DisplayName("Java | ParameterName")
final public class ParameterNameTest {
@Test
@DisplayName("derive works when given existing names")
public void withExisting() {
ParameterName names = new ParameterName();
assertEquals(":taco", names.derive(":taco"), "Name should have been :taco");
assertEquals(":field0", names.derive(null), "Counter should not have advanced for named field");
}
@Test
@DisplayName("derive works when given all anonymous fields")
public void allAnonymous() {
ParameterName names = new ParameterName();
assertEquals(":field0", names.derive(null), "Anonymous field name should have been returned");
assertEquals(":field1", names.derive(null), "Counter should have advanced from previous call");
assertEquals(":field2", names.derive(null), "Counter should have advanced from previous call");
assertEquals(":field3", names.derive(null), "Counter should have advanced from previous call");
}
}

View File

@ -0,0 +1,40 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.DocumentException;
import solutions.bitbadger.documents.Parameter;
import solutions.bitbadger.documents.ParameterType;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Parameter` class
*/
@DisplayName("Java | Parameter")
final public class ParameterTest {
@Test
@DisplayName("Construction with colon-prefixed name")
public void ctorWithColon() {
Parameter<String> p = new Parameter<>(":test", ParameterType.STRING, "ABC");
assertEquals(":test", p.getName(), "Parameter name was incorrect");
assertEquals(ParameterType.STRING, p.getType(), "Parameter type was incorrect");
assertEquals("ABC", p.getValue(), "Parameter value was incorrect");
}
@Test
@DisplayName("Construction with at-sign-prefixed name")
public void ctorWithAtSign() {
Parameter<String> p = new Parameter<>("@yo", ParameterType.NUMBER, null);
assertEquals("@yo", p.getName(), "Parameter name was incorrect");
assertEquals(ParameterType.NUMBER, p.getType(), "Parameter type was incorrect");
assertNull(p.getValue(), "Parameter value was incorrect");
}
@Test
@DisplayName("Construction fails with incorrect prefix")
public void ctorFailsForPrefix() {
assertThrows(DocumentException.class, () -> new Parameter<>("it", ParameterType.JSON, ""));
}
}

View File

@ -0,0 +1,121 @@
package solutions.bitbadger.documents.java;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import solutions.bitbadger.documents.*;
import java.util.Collection;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for the `Parameters` object
*/
@DisplayName("Java | Parameters")
final public class ParametersTest {
/**
* Reset the dialect
*/
@AfterEach
public void cleanUp() {
Configuration.setConnectionString(null);
}
@Test
@DisplayName("nameFields works with no changes")
public void nameFieldsNoChange() {
List<Field<?>> fields = List.of(Field.equal("a", "", ":test"), Field.exists("q"), Field.equal("b", "", ":me"));
Field<?>[] named = Parameters.nameFields(fields).toArray(new Field<?>[] { });
assertEquals(fields.size(), named.length, "There should have been 3 fields in the list");
assertSame(fields.get(0), named[0], "The first field should be the same");
assertSame(fields.get(1), named[1], "The second field should be the same");
assertSame(fields.get(2), named[2], "The third field should be the same");
}
@Test
@DisplayName("nameFields works when changing fields")
public void nameFieldsChange() {
List<Field<?>> fields = List.of(
Field.equal("a", ""), Field.equal("e", "", ":hi"), Field.equal("b", ""), Field.notExists("z"));
Field<?>[] named = Parameters.nameFields(fields).toArray(new Field<?>[] { });
assertEquals(fields.size(), named.length, "There should have been 4 fields in the list");
assertNotSame(fields.get(0), named[0], "The first field should not be the same");
assertEquals(":field0", named[0].getParameterName(), "First parameter name incorrect");
assertSame(fields.get(1), named[1], "The second field should be the same");
assertNotSame(fields.get(2), named[2], "The third field should not be the same");
assertEquals(":field1", named[2].getParameterName(), "Third parameter name incorrect");
assertSame(fields.get(3), named[3], "The fourth field should be the same");
}
@Test
@DisplayName("replaceNamesInQuery replaces successfully")
public void replaceNamesInQuery() {
List<Parameter<?>> parameters = List.of(new Parameter<>(":data", ParameterType.JSON, "{}"),
new Parameter<>(":data_ext", ParameterType.STRING, ""));
String query =
"SELECT data, data_ext FROM tbl WHERE data = :data AND data_ext = :data_ext AND more_data = :data";
assertEquals("SELECT data, data_ext FROM tbl WHERE data = ? AND data_ext = ? AND more_data = ?",
Parameters.replaceNamesInQuery(query, parameters), "Parameters not replaced correctly");
}
@Test
@DisplayName("fieldNames generates a single parameter (PostgreSQL)")
public void fieldNamesSinglePostgres() {
Configuration.setConnectionString(":postgresql:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[] { });
assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
assertEquals("{test}", nameParams[0].getValue(), "The parameter value is incorrect");
}
@Test
@DisplayName("fieldNames generates multiple parameters (PostgreSQL)")
public void fieldNamesMultiplePostgres() {
Configuration.setConnectionString(":postgresql:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
.toArray(new Parameter<?>[] { });
assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
assertEquals("{test,this,today}", nameParams[0].getValue(), "The parameter value is incorrect");
}
@Test
@DisplayName("fieldNames generates a single parameter (SQLite)")
public void fieldNamesSingleSQLite() {
Configuration.setConnectionString(":sqlite:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test")).toArray(new Parameter<?>[] { });
assertEquals(1, nameParams.length, "There should be one name parameter");
assertEquals(":name0", nameParams[0].getName(), "The parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The parameter type is incorrect");
assertEquals("test", nameParams[0].getValue(), "The parameter value is incorrect");
}
@Test
@DisplayName("fieldNames generates multiple parameters (SQLite)")
public void fieldNamesMultipleSQLite() {
Configuration.setConnectionString(":sqlite:");
Parameter<?>[] nameParams = Parameters.fieldNames(List.of("test", "this", "today"))
.toArray(new Parameter<?>[] { });
assertEquals(3, nameParams.length, "There should be one name parameter");
assertEquals(":name0", nameParams[0].getName(), "The first parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[0].getType(), "The first parameter type is incorrect");
assertEquals("test", nameParams[0].getValue(), "The first parameter value is incorrect");
assertEquals(":name1", nameParams[1].getName(), "The second parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[1].getType(), "The second parameter type is incorrect");
assertEquals("this", nameParams[1].getValue(), "The second parameter value is incorrect");
assertEquals(":name2", nameParams[2].getName(), "The third parameter name is incorrect");
assertEquals(ParameterType.STRING, nameParams[2].getType(), "The third parameter type is incorrect");
assertEquals("today", nameParams[2].getValue(), "The third parameter value is incorrect");
}
@Test
@DisplayName("fieldNames fails if dialect not set")
public void fieldNamesFails() {
assertThrows(DocumentException.class, () -> Parameters.fieldNames(List.of()));
}
}

View File

@ -0,0 +1,18 @@
package solutions.bitbadger.documents.java.testDocs;
public class ByteIdClass {
private byte id;
public byte getId() {
return id;
}
public void setId(byte id) {
this.id = id;
}
public ByteIdClass(byte id) {
this.id = id;
}
}

View File

@ -0,0 +1,18 @@
package solutions.bitbadger.documents.java.testDocs;
public class IntIdClass {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public IntIdClass(int id) {
this.id = id;
}
}

View File

@ -0,0 +1,18 @@
package solutions.bitbadger.documents.java.testDocs;
public class LongIdClass {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public LongIdClass(long id) {
this.id = id;
}
}

View File

@ -0,0 +1,18 @@
package solutions.bitbadger.documents.java.testDocs;
public class ShortIdClass {
private short id;
public short getId() {
return id;
}
public void setId(short id) {
this.id = id;
}
public ShortIdClass(short id) {
this.id = id;
}
}

View File

@ -0,0 +1,18 @@
package solutions.bitbadger.documents.java.testDocs;
public class StringIdClass {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public StringIdClass(String id) {
this.id = id;
}
}

View File

@ -11,7 +11,7 @@ import kotlin.test.assertTrue
/** /**
* Unit tests for the `AutoId` enum * Unit tests for the `AutoId` enum
*/ */
@DisplayName("AutoId") @DisplayName("Kotlin | AutoId")
class AutoIdTest { class AutoIdTest {
@Test @Test
@ -66,8 +66,10 @@ class AutoIdTest {
@Test @Test
@DisplayName("needsAutoId returns false for Number strategy and byte ID of non-0") @DisplayName("needsAutoId returns false for Number strategy and byte ID of non-0")
fun needsAutoIdFalseForByteWithNonZero() = fun needsAutoIdFalseForByteWithNonZero() =
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, ByteIdClass(77), "id"), assertFalse(
"Number Auto ID with 77 should return false") AutoId.needsAutoId(AutoId.NUMBER, ByteIdClass(77), "id"),
"Number Auto ID with 77 should return false"
)
@Test @Test
@DisplayName("needsAutoId returns true for Number strategy and short ID of 0") @DisplayName("needsAutoId returns true for Number strategy and short ID of 0")
@ -77,8 +79,10 @@ class AutoIdTest {
@Test @Test
@DisplayName("needsAutoId returns false for Number strategy and short ID of non-0") @DisplayName("needsAutoId returns false for Number strategy and short ID of non-0")
fun needsAutoIdFalseForShortWithNonZero() = fun needsAutoIdFalseForShortWithNonZero() =
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, ShortIdClass(31), "id"), assertFalse(
"Number Auto ID with 31 should return false") AutoId.needsAutoId(AutoId.NUMBER, ShortIdClass(31), "id"),
"Number Auto ID with 31 should return false"
)
@Test @Test
@DisplayName("needsAutoId returns true for Number strategy and int ID of 0") @DisplayName("needsAutoId returns true for Number strategy and int ID of 0")
@ -98,7 +102,10 @@ class AutoIdTest {
@Test @Test
@DisplayName("needsAutoId returns false for Number strategy and long ID of non-0") @DisplayName("needsAutoId returns false for Number strategy and long ID of non-0")
fun needsAutoIdFalseForLongWithNonZero() = fun needsAutoIdFalseForLongWithNonZero() =
assertFalse(AutoId.needsAutoId(AutoId.NUMBER, IntIdClass(2), "id"), "Number Auto ID with 2 should return false") assertFalse(
AutoId.needsAutoId(AutoId.NUMBER, LongIdClass(2), "id"),
"Number Auto ID with 2 should return false"
)
@Test @Test
@DisplayName("needsAutoId fails for Number strategy and non-number ID") @DisplayName("needsAutoId fails for Number strategy and non-number ID")
@ -109,14 +116,18 @@ class AutoIdTest {
@Test @Test
@DisplayName("needsAutoId returns true for UUID strategy and blank ID") @DisplayName("needsAutoId returns true for UUID strategy and blank ID")
fun needsAutoIdTrueForUUIDWithBlank() = fun needsAutoIdTrueForUUIDWithBlank() =
assertTrue(AutoId.needsAutoId(AutoId.UUID, StringIdClass(""), "id"), assertTrue(
"UUID Auto ID with blank should return true") AutoId.needsAutoId(AutoId.UUID, StringIdClass(""), "id"),
"UUID Auto ID with blank should return true"
)
@Test @Test
@DisplayName("needsAutoId returns false for UUID strategy and non-blank ID") @DisplayName("needsAutoId returns false for UUID strategy and non-blank ID")
fun needsAutoIdFalseForUUIDNotBlank() = fun needsAutoIdFalseForUUIDNotBlank() =
assertFalse(AutoId.needsAutoId(AutoId.UUID, StringIdClass("howdy"), "id"), assertFalse(
"UUID Auto ID with non-blank should return false") AutoId.needsAutoId(AutoId.UUID, StringIdClass("howdy"), "id"),
"UUID Auto ID with non-blank should return false"
)
@Test @Test
@DisplayName("needsAutoId fails for UUID strategy and non-string ID") @DisplayName("needsAutoId fails for UUID strategy and non-string ID")
@ -127,14 +138,18 @@ class AutoIdTest {
@Test @Test
@DisplayName("needsAutoId returns true for Random String strategy and blank ID") @DisplayName("needsAutoId returns true for Random String strategy and blank ID")
fun needsAutoIdTrueForRandomWithBlank() = fun needsAutoIdTrueForRandomWithBlank() =
assertTrue(AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass(""), "id"), assertTrue(
"Random String Auto ID with blank should return true") AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass(""), "id"),
"Random String Auto ID with blank should return true"
)
@Test @Test
@DisplayName("needsAutoId returns false for Random String strategy and non-blank ID") @DisplayName("needsAutoId returns false for Random String strategy and non-blank ID")
fun needsAutoIdFalseForRandomNotBlank() = fun needsAutoIdFalseForRandomNotBlank() =
assertFalse(AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass("full"), "id"), assertFalse(
"Random String Auto ID with non-blank should return false") AutoId.needsAutoId(AutoId.RANDOM_STRING, StringIdClass("full"), "id"),
"Random String Auto ID with non-blank should return false"
)
@Test @Test
@DisplayName("needsAutoId fails for Random String strategy and non-string ID") @DisplayName("needsAutoId fails for Random String strategy and non-string ID")

View File

@ -10,7 +10,7 @@ import kotlin.test.assertTrue
/** /**
* Unit tests for the `Configuration` object * Unit tests for the `Configuration` object
*/ */
@DisplayName("Configuration") @DisplayName("Kotlin | Configuration")
class ConfigurationTest { class ConfigurationTest {
@Test @Test

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `DocumentIndex` enum * Unit tests for the `DocumentIndex` enum
*/ */
@DisplayName("Op") @DisplayName("Kotlin | DocumentIndex")
class DocumentIndexTest { class DocumentIndexTest {
@Test @Test

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `FieldMatch` enum * Unit tests for the `FieldMatch` enum
*/ */
@DisplayName("FieldMatch") @DisplayName("Kotlin | FieldMatch")
class FieldMatchTest { class FieldMatchTest {
@Test @Test

View File

@ -11,7 +11,7 @@ import kotlin.test.assertNull
/** /**
* Unit tests for the `Field` class * Unit tests for the `Field` class
*/ */
@DisplayName("Field") @DisplayName("Kotlin | Field")
class FieldTest { class FieldTest {
/** /**

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `Op` enum * Unit tests for the `Op` enum
*/ */
@DisplayName("Op") @DisplayName("Kotlin | Op")
class OpTest { class OpTest {
@Test @Test

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
/** /**
* Unit tests for the `ParameterName` class * Unit tests for the `ParameterName` class
*/ */
@DisplayName("ParameterName") @DisplayName("Kotlin | ParameterName")
class ParameterNameTest { class ParameterNameTest {
@Test @Test

View File

@ -9,7 +9,7 @@ import kotlin.test.assertNull
/** /**
* Unit tests for the `Parameter` class * Unit tests for the `Parameter` class
*/ */
@DisplayName("Parameter") @DisplayName("Kotlin | Parameter")
class ParameterTest { class ParameterTest {
@Test @Test

View File

@ -11,7 +11,7 @@ import kotlin.test.assertSame
/** /**
* Unit tests for the `Parameters` object * Unit tests for the `Parameters` object
*/ */
@DisplayName("Parameters") @DisplayName("Kotlin | Parameters")
class ParametersTest { class ParametersTest {
/** /**