diff options
Diffstat (limited to 'src/ext_depends_cgi/d2sqlite3/source/tests.d')
-rw-r--r-- | src/ext_depends_cgi/d2sqlite3/source/tests.d | 931 |
1 files changed, 0 insertions, 931 deletions
diff --git a/src/ext_depends_cgi/d2sqlite3/source/tests.d b/src/ext_depends_cgi/d2sqlite3/source/tests.d deleted file mode 100644 index ff20af1..0000000 --- a/src/ext_depends_cgi/d2sqlite3/source/tests.d +++ /dev/null @@ -1,931 +0,0 @@ -module tests.d; - -version (unittest): - -import d2sqlite3; -import std.algorithm; -import std.exception : assertThrown, assertNotThrown; -import std.string : format; -import std.typecons : Nullable; -import std.conv : hexString; - -unittest // Test version of SQLite library -{ - import std.string : startsWith; - assert(versionString.startsWith("3.")); - assert(versionNumber >= 3_008_007); -} - -unittest // COV -{ - auto ts = threadSafe; -} - -unittest // Configuration logging and db.close() -{ - static extern (C) void loggerCallback(void* arg, int code, const(char)* msg) nothrow - { - ++*(cast(int*) arg); - } - - int marker = 42; - - shutdown(); - config(SQLITE_CONFIG_MULTITHREAD); - config(SQLITE_CONFIG_LOG, &loggerCallback, &marker); - initialize(); - - { - auto db = Database(":memory:"); - try - { - db.run("DROP TABLE wtf"); - } - catch (Exception e) - { - } - db.close(); - } - assert(marker == 43); - - shutdown(); - config(SQLITE_CONFIG_LOG, null, null); - initialize(); - - { - auto db = Database(":memory:"); - try - { - db.run("DROP TABLE wtf"); - } - catch (Exception e) - { - } - } - assert(marker == 43); -} - -unittest // Database.tableColumnMetadata() -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, - val FLOAT NOT NULL)"); - assert(db.tableColumnMetadata("test", "id") == - TableColumnMetadata("INTEGER", "BINARY", false, true, true)); - assert(db.tableColumnMetadata("test", "val") == - TableColumnMetadata("FLOAT", "BINARY", true, false, false)); -} - -unittest // Database.run() -{ - auto db = Database(":memory:"); - int i; - db.run(`SELECT 1; SELECT 2;`, (ResultRange r) { i = r.oneValue!int; return false; }); - assert(i == 1); -} - -unittest // Database.errorCode() -{ - auto db = Database(":memory:"); - db.run(`SELECT 1;`); - assert(db.errorCode == SQLITE_OK); - try - db.run(`DROP TABLE non_existent`); - catch (SqliteException e) - assert(db.errorCode == SQLITE_ERROR); -} - -unittest // Database.config -{ - auto db = Database(":memory:"); - db.run(` - CREATE TABLE test (val INTEGER); - CREATE TRIGGER test_trig BEFORE INSERT ON test - BEGIN - SELECT RAISE(FAIL, 'Test failed'); - END; - `); - int res = 42; - db.config(SQLITE_DBCONFIG_ENABLE_TRIGGER, 0, &res); - assert(res == 0); - db.execute("INSERT INTO test (val) VALUES (1)"); -} - -unittest // Database.createFunction(ColumnData[]...) -{ - string myList(ColumnData[] args...) - { - import std.array : appender; - import std.string : format, join; - - auto app = appender!(string[]); - foreach (arg; args) - { - if (arg.type == SqliteType.TEXT) - app.put(`"%s"`.format(arg)); - else - app.put("%s".format(arg)); - } - return app.data.join(", "); - } - auto db = Database(":memory:"); - db.createFunction("my_list", &myList); - auto list = db.execute("SELECT my_list(42, 3.14, 'text', x'00FF', NULL)").oneValue!string; - assert(list == `42, 3.14, "text", [0, 255], null`, list); -} - -unittest // Database.createFunction() exceptions -{ - import std.exception : assertThrown; - - int myFun(int a, int b = 1) - { - return a * b; - } - - auto db = Database(":memory:"); - db.createFunction("myFun", &myFun); - assertThrown!SqliteException(db.execute("SELECT myFun()")); - assertThrown!SqliteException(db.execute("SELECT myFun(1, 2, 3)")); - assert(db.execute("SELECT myFun(5)").oneValue!int == 5); - assert(db.execute("SELECT myFun(5, 2)").oneValue!int == 10); - - db.createFunction("myFun", null); - assertThrown!SqliteException(db.execute("SELECT myFun(5)")); - assertThrown!SqliteException(db.execute("SELECT myFun(5, 2)")); -} - -unittest // Database.setUpdateHook() -{ - int i; - auto db = Database(":memory:"); - db.setUpdateHook((int type, string dbName, string tableName, long rowid) { - assert(type == SQLITE_INSERT); - assert(dbName == "main"); - assert(tableName == "test"); - assert(rowid == 1); - i = 42; - }); - db.run("CREATE TABLE test (val INTEGER); - INSERT INTO test VALUES (100)"); - assert(i == 42); - db.setUpdateHook(null); -} - -unittest // Database commit and rollback hooks -{ - int i; - auto db = Database(":memory:"); - db.setCommitHook({ i = 42; return SQLITE_OK; }); - db.setRollbackHook({ i = 666; }); - db.begin(); - db.execute("CREATE TABLE test (val INTEGER)"); - db.rollback(); - assert(i == 666); - db.begin(); - db.execute("CREATE TABLE test (val INTEGER)"); - db.commit(); - assert(i == 42); - db.setCommitHook(null); - db.setRollbackHook(null); -} - -unittest // Miscellaneous functions -{ - auto db = Database(":memory:"); - assert(db.attachedFilePath("main") is null); - assert(!db.isReadOnly); - db.close(); -} - -unittest // Execute an SQL statement -{ - auto db = Database(":memory:"); - db.run(""); - db.run("-- This is a comment!"); - db.run(";"); - db.run("ANALYZE; VACUUM;"); -} - -unittest // Unexpected multiple statements -{ - auto db = Database(":memory:"); - db.execute("BEGIN; CREATE TABLE test (val INTEGER); ROLLBACK;"); - assertThrown(db.execute("DROP TABLE test")); - - db.execute("CREATE TABLE test (val INTEGER); DROP TABLE test;"); - assertNotThrown(db.execute("DROP TABLE test")); - - db.execute("SELECT 1; CREATE TABLE test (val INTEGER); DROP TABLE test;"); - assertThrown(db.execute("DROP TABLE test")); -} - -unittest // Multiple statements with callback -{ - import std.array : appender; - auto db = Database(":memory:"); - auto test = appender!string; - db.run("SELECT 1, 2, 3; SELECT 'A', 'B', 'C';", (ResultRange r) { - foreach (col; r.front) - test.put(col.as!string); - return true; - }); - assert(test.data == "123ABC"); -} - -unittest // Different arguments and result types with createFunction -{ - auto db = Database(":memory:"); - - T display(T)(T value) - { - return value; - } - - db.createFunction("display_integer", &display!int); - db.createFunction("display_float", &display!double); - db.createFunction("display_text", &display!string); - db.createFunction("display_blob", &display!Blob); - - assert(db.execute("SELECT display_integer(42)").oneValue!int == 42); - assert(db.execute("SELECT display_float(3.14)").oneValue!double == 3.14); - assert(db.execute("SELECT display_text('ABC')").oneValue!string == "ABC"); - assert(db.execute("SELECT display_blob(x'ABCD')").oneValue!Blob == cast(Blob) hexString!"ABCD"); - - assert(db.execute("SELECT display_integer(NULL)").oneValue!int == 0); - assert(db.execute("SELECT display_float(NULL)").oneValue!double == 0.0); - assert(db.execute("SELECT display_text(NULL)").oneValue!string is null); - assert(db.execute("SELECT display_blob(NULL)").oneValue!(Blob) is null); -} - -unittest // Different Nullable argument types with createFunction -{ - auto db = Database(":memory:"); - - auto display(T : Nullable!U, U...)(T value) - { - if (value.isNull) - return T.init; - return value; - } - - db.createFunction("display_integer", &display!(Nullable!int)); - db.createFunction("display_float", &display!(Nullable!double)); - db.createFunction("display_text", &display!(Nullable!string)); - db.createFunction("display_blob", &display!(Nullable!Blob)); - - assert(db.execute("SELECT display_integer(42)").oneValue!(Nullable!int) == 42); - assert(db.execute("SELECT display_float(3.14)").oneValue!(Nullable!double) == 3.14); - assert(db.execute("SELECT display_text('ABC')").oneValue!(Nullable!string) == "ABC"); - assert(db.execute("SELECT display_blob(x'ABCD')").oneValue!(Nullable!Blob) == cast(Blob) hexString!"ABCD"); - - assert(db.execute("SELECT display_integer(NULL)").oneValue!(Nullable!int).isNull); - assert(db.execute("SELECT display_float(NULL)").oneValue!(Nullable!double).isNull); - assert(db.execute("SELECT display_text(NULL)").oneValue!(Nullable!string).isNull); - assert(db.execute("SELECT display_blob(NULL)").oneValue!(Nullable!Blob).isNull); -} - -unittest // Callable struct with createFunction -{ - import std.functional : toDelegate; - - struct Fun - { - int factor; - - this(int factor) - { - this.factor = factor; - } - - int opCall(int value) - { - return value * factor; - } - } - - auto f = Fun(2); - auto db = Database(":memory:"); - db.createFunction("my_fun", toDelegate(f)); - assert(db.execute("SELECT my_fun(4)").oneValue!int == 8); -} - -unittest // Callbacks -{ - bool wasTraced = false; - bool wasProfiled = false; - bool hasProgressed = false; - - auto db = Database(":memory:"); - db.setTraceCallback((string s) { wasTraced = true; }); - db.execute("SELECT * FROM sqlite_master;"); - assert(wasTraced); - db.setProfileCallback((string s, ulong t) { wasProfiled = true; }); - db.execute("SELECT * FROM sqlite_master;"); - assert(wasProfiled); - - db.setProgressHandler(1, { hasProgressed = true; return 0; }); - db.execute("SELECT * FROM sqlite_master;"); - assert(hasProgressed); -} - -unittest // Statement.oneValue() -{ - Statement statement; - { - auto db = Database(":memory:"); - statement = db.prepare(" SELECT 42 "); - } - assert(statement.execute.oneValue!int == 42); -} - -unittest // Statement.finalize() -{ - auto db = Database(":memory:"); - auto statement = db.prepare(" SELECT 42 "); - statement.finalize(); -} - -unittest // Simple parameters binding -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (val INTEGER)"); - - auto statement = db.prepare("INSERT INTO test (val) VALUES (?)"); - statement.bind(1, 36); - statement.clearBindings(); - statement.bind(1, 42); - statement.execute(); - statement.reset(); - statement.bind(1, 42); - statement.execute(); - - assert(db.lastInsertRowid == 2); - assert(db.changes == 1); - assert(db.totalChanges == 2); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - assert(row.peek!int(0) == 42); -} - -unittest // Multiple parameters binding -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (i INTEGER, f FLOAT, t TEXT)"); - auto statement = db.prepare("INSERT INTO test (i, f, t) VALUES (:i, @f, $t)"); - - assert(statement.parameterCount == 3); - assert(statement.parameterName(2) == "@f"); - assert(statement.parameterIndex("$t") == 3); - assert(statement.parameterIndex(":foo") == 0); - - statement.bind("$t", "TEXT"); - statement.bind(":i", 42); - statement.bind("@f", 3.14); - statement.execute(); - statement.reset(); - statement.bind(1, 42); - statement.bind(2, 3.14); - statement.bind(3, "TEXT"); - statement.execute(); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!int("i") == 42); - assert(row.peek!double("f") == 3.14); - assert(row.peek!string("t") == "TEXT"); - } -} - -// Binding/peeking structs with `toString` and `fromString` -unittest -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (val TEXT)"); - - static struct ToStringSink { - string value; - void toString(scope void delegate(in char[]) sink) const - { - sink(this.value); - } - } - - static struct ToStringMethod { - string value; - string toString() const - { - return this.value; - } - } - - auto statement = db.prepare("INSERT INTO test (val) VALUES (?)"); - statement.bind(1, ToStringMethod("oldmethod")); - statement.clearBindings(); - statement.bind(1, ToStringMethod("method")); - statement.execute(); - statement.reset(); - statement.bind(1, ToStringSink("sink")); - statement.execute(); - - assert(db.lastInsertRowid == 2); - assert(db.changes == 1); - assert(db.totalChanges == 2); - - auto results = db.execute("SELECT * FROM test"); - results.equal!((a, b) => a.peek!string(0) == b)(["method", "sink"]); -} - -unittest // Multiple parameters binding: tuples -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (i INTEGER, f FLOAT, t TEXT)"); - auto statement = db.prepare("INSERT INTO test (i, f, t) VALUES (?, ?, ?)"); - statement.bindAll(42, 3.14, "TEXT"); - statement.execute(); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!int(0) == 42); - assert(row.peek!double(1) == 3.14); - assert(row.peek!string(2) == "TEXT"); - } -} - -unittest // Binding/peeking integral values -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (val INTEGER)"); - - auto statement = db.prepare("INSERT INTO test (val) VALUES (?)"); - statement.inject(cast(byte) 42); - statement.inject(42U); - statement.inject(42UL); - statement.inject('\x2A'); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - assert(row.peek!long(0) == 42); -} - -void foobar() // Binding/peeking floating point values -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (val FLOAT)"); - - auto statement = db.prepare("INSERT INTO test (val) VALUES (?)"); - statement.inject(42.0F); - statement.inject(42.0); - statement.inject(42.0L); - statement.inject("42"); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - assert(row.peek!double(0) == 42.0); -} - -unittest // Binding/peeking text values -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (val TEXT); - INSERT INTO test (val) VALUES ('I am a text.')"); - - auto results = db.execute("SELECT * FROM test"); - assert(results.front.peek!(string, PeekMode.slice)(0) == "I am a text."); - assert(results.front.peek!(string, PeekMode.copy)(0) == "I am a text."); - - import std.exception : assertThrown; - import std.variant : VariantException; - assertThrown!VariantException(results.front[0].as!Blob); -} - -unittest // Binding/peeking blob values -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (val BLOB)"); - - auto statement = db.prepare("INSERT INTO test (val) VALUES (?)"); - auto array = cast(Blob) [1, 2, 3]; - statement.inject(array); - ubyte[3] sarray = [1, 2, 3]; - statement.inject(sarray); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.peek!(Blob, PeekMode.slice)(0) == [1, 2, 3]); - assert(row[0].as!Blob == [1, 2, 3]); - } -} - -unittest // Struct injecting -{ - static struct Test - { - int i; - double f; - string t; - } - - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (i INTEGER, f FLOAT, t TEXT)"); - auto statement = db.prepare("INSERT INTO test (i, f, t) VALUES (?, ?, ?)"); - auto test = Test(42, 3.14, "TEXT"); - statement.inject(test); - statement.inject(Test(42, 3.14, "TEXT")); - auto itest = cast(immutable) Test(42, 3.14, "TEXT"); - statement.inject(itest); - - auto results = db.execute("SELECT * FROM test"); - assert(!results.empty); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!int(0) == 42); - assert(row.peek!double(1) == 3.14); - assert(row.peek!string(2) == "TEXT"); - } -} - -unittest // Iterable struct injecting -{ - import std.range : iota; - - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (a INTEGER, b INTEGER, c INTEGER)"); - auto statement = db.prepare("INSERT INTO test (a, b, c) VALUES (?, ?, ?)"); - statement.inject(iota(0, 3)); - - auto results = db.execute("SELECT * FROM test"); - assert(!results.empty); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!int(0) == 0); - assert(row.peek!int(1) == 1); - assert(row.peek!int(2) == 2); - } -} - -unittest // Injecting nullable -{ - import std.array : array; - - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (i INTEGER, s TEXT)"); - auto statement = db.prepare("INSERT INTO test (i, s) VALUES (?, ?)"); - statement.inject(Nullable!int(1), "one"); - statement = db.prepare("INSERT INTO test (i) VALUES (?)"); - statement.inject(Nullable!int.init); - - auto results = db.execute("SELECT i FROM test ORDER BY rowid"); - assert(results.equal!((a, b) => a.peek!(Nullable!int)(0) == b)( - [ Nullable!int(1), Nullable!int.init ] )); -} - -unittest // Injecting tuple -{ - import std.typecons : tuple; - - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (i INTEGER, f FLOAT, t TEXT)"); - auto statement = db.prepare("INSERT INTO test (i, f, t) VALUES (?, ?, ?)"); - statement.inject(tuple(42, 3.14, "TEXT")); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!int(0) == 42); - assert(row.peek!double(1) == 3.14); - assert(row.peek!string(2) == "TEXT"); - } -} - -unittest // Injecting dict -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (a TEXT, b TEXT, c TEXT)"); - auto statement = db.prepare("INSERT INTO test (c, b, a) VALUES (:c, :b, :a)"); - statement.inject([":a":"a", ":b":"b", ":c":"c"]); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.length == 3); - assert(row.peek!string(0) == "a"); - assert(row.peek!string(1) == "b"); - assert(row.peek!string(2) == "c"); - } -} - -unittest // Binding Nullable -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (a, b, c, d, e);"); - - auto statement = db.prepare("INSERT INTO test (a,b,c,d,e) VALUES (?,?,?,?,?)"); - statement.bind(1, Nullable!int(123)); - statement.bind(2, Nullable!int()); - statement.bind(3, Nullable!(uint, 0)(42)); - statement.bind(4, Nullable!(uint, 0)()); - statement.bind(5, Nullable!bool(false)); - statement.execute(); - - auto results = db.execute("SELECT * FROM test"); - foreach (row; results) - { - assert(row.length == 5); - assert(row.peek!int(0) == 123); - assert(row.columnType(1) == SqliteType.NULL); - assert(row.peek!int(2) == 42); - assert(row.columnType(3) == SqliteType.NULL); - assert(!row.peek!bool(4)); - } -} - -unittest // Peeking Nullable -{ - auto db = Database(":memory:"); - auto results = db.execute("SELECT 1, NULL, 8.5, NULL"); - foreach (row; results) - { - assert(row.length == 4); - assert(row.peek!(Nullable!double)(2).get == 8.5); - assert(row.peek!(Nullable!double)(3).isNull); - assert(row.peek!(Nullable!(int, 0))(0).get == 1); - assert(row.peek!(Nullable!(int, 0))(1).isNull); - } -} - -unittest // GC anchoring test -{ - import core.memory : GC; - - auto db = Database(":memory:"); - auto stmt = db.prepare("SELECT ?"); - - auto str = ("I am test string").dup; - stmt.bind(1, str); - str = null; - - foreach (_; 0..3) - { - GC.collect(); - GC.minimize(); - } - - ResultRange results = stmt.execute(); - foreach(row; results) - { - assert(row.length == 1); - assert(row.peek!string(0) == "I am test string"); - } -} - -version (unittest) // ResultRange is an input range of Row -{ - import std.range.primitives : isInputRange, ElementType; - static assert(isInputRange!ResultRange); - static assert(is(ElementType!ResultRange == Row)); -} - -unittest // Statement error -{ - auto db = Database(":memory:"); - db.execute("CREATE TABLE test (val INTEGER NOT NULL)"); - auto stmt = db.prepare("INSERT INTO test (val) VALUES (?)"); - stmt.bind(1, null); - import std.exception : assertThrown; - assertThrown!SqliteException(stmt.execute()); -} - -version (unittest) // Row is a random access range of ColumnData -{ - import std.range.primitives : isRandomAccessRange, ElementType; - static assert(isRandomAccessRange!Row); - static assert(is(ElementType!Row == ColumnData)); -} - -unittest // Row.init -{ - import core.exception : AssertError; - - Row row; - assert(row.empty); - assertThrown!AssertError(row.front); - assertThrown!AssertError(row.back); - assertThrown!AssertError(row.popFront); - assertThrown!AssertError(row.popBack); - assertThrown!AssertError(row[""]); - assertThrown!AssertError(row.peek!long(0)); -} - -unittest // Peek -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (value); - INSERT INTO test VALUES (NULL); - INSERT INTO test VALUES (42); - INSERT INTO test VALUES (3.14); - INSERT INTO test VALUES ('ABC'); - INSERT INTO test VALUES (x'DEADBEEF');"); - - import std.math : isNaN; - auto results = db.execute("SELECT * FROM test"); - auto row = results.front; - assert(row.peek!long(0) == 0); - assert(row.peek!double(0) == 0); - assert(row.peek!string(0) is null); - assert(row.peek!Blob(0) is null); - results.popFront(); - row = results.front; - assert(row.peek!long(0) == 42); - assert(row.peek!double(0) == 42); - assert(row.peek!string(0) == "42"); - assert(row.peek!Blob(0) == cast(Blob) "42"); - results.popFront(); - row = results.front; - assert(row.peek!long(0) == 3); - assert(row.peek!double(0) == 3.14); - assert(row.peek!string(0) == "3.14"); - assert(row.peek!Blob(0) == cast(Blob) "3.14"); - results.popFront(); - row = results.front; - assert(row.peek!long(0) == 0); - assert(row.peek!double(0) == 0.0); - assert(row.peek!string(0) == "ABC"); - assert(row.peek!Blob(0) == cast(Blob) "ABC"); - results.popFront(); - row = results.front; - assert(row.peek!long(0) == 0); - assert(row.peek!double(0) == 0.0); - assert(row.peek!string(0) == hexString!"DEADBEEF"); - assert(row.peek!Blob(0) == cast(Blob) hexString!"DEADBEEF"); -} - -unittest // Peeking NULL values -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (val TEXT); - INSERT INTO test (val) VALUES (NULL)"); - - auto results = db.execute("SELECT * FROM test"); - assert(results.front.peek!bool(0) == false); - assert(results.front.peek!long(0) == 0); - assert(results.front.peek!double(0) == 0); - assert(results.front.peek!string(0) is null); - assert(results.front.peek!Blob(0) is null); -} - -unittest // Row life-time -{ - auto db = Database(":memory:"); - auto row = db.execute("SELECT 1 AS one").front; - assert(row[0].as!long == 1); - assert(row["one"].as!long == 1); -} - -unittest // PeekMode -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (value); - INSERT INTO test VALUES (x'01020304'); - INSERT INTO test VALUES (x'0A0B0C0D');"); - - auto results = db.execute("SELECT * FROM test"); - auto row = results.front; - auto b1 = row.peek!(Blob, PeekMode.copy)(0); - auto b2 = row.peek!(Blob, PeekMode.slice)(0); - results.popFront(); - row = results.front; - auto b3 = row.peek!(Blob, PeekMode.slice)(0); - auto b4 = row.peek!(Nullable!Blob, PeekMode.copy)(0); - assert(b1 == cast(Blob) hexString!"01020304"); - // assert(b2 != cast(Blob) x"01020304"); // PASS if SQLite reuses internal buffer - // assert(b2 == cast(Blob) x"0A0B0C0D"); // PASS (idem) - assert(b3 == cast(Blob) hexString!"0A0B0C0D"); - assert(!b4.isNull && b4 == cast(Blob) hexString!"0A0B0C0D"); -} - -unittest // Row random-access range interface -{ - import std.array : front, popFront; - - auto db = Database(":memory:"); - db.run("CREATE TABLE test (a INTEGER, b INTEGER, c INTEGER, d INTEGER); - INSERT INTO test VALUES (1, 2, 3, 4); - INSERT INTO test VALUES (5, 6, 7, 8);"); - - { - auto results = db.execute("SELECT * FROM test"); - auto values = [1, 2, 3, 4, 5, 6, 7, 8]; - foreach (row; results) - { - while (!row.empty) - { - assert(row.front.as!int == values.front); - row.popFront(); - values.popFront(); - } - } - } - - { - auto results = db.execute("SELECT * FROM test"); - auto values = [4, 3, 2, 1, 8, 7, 6, 5]; - foreach (row; results) - { - while (!row.empty) - { - assert(row.back.as!int == values.front); - row.popBack(); - values.popFront(); - } - } - } - - { - auto row = db.execute("SELECT * FROM test").front; - row.popFront(); - auto copy = row.save(); - row.popFront(); - assert(row.front.as!int == 3); - assert(copy.front.as!int == 2); - } -} - -unittest // ColumnData.init -{ - import core.exception : AssertError; - ColumnData data; - assertThrown!AssertError(data.type); - assertThrown!AssertError(data.as!string); -} - -unittest // ColumnData-compatible types -{ - import std.meta : AliasSeq; - - alias AllCases = AliasSeq!(bool, true, int, int.max, float, float.epsilon, - real, 42.0L, string, "おはよう!", const(ubyte)[], [0x00, 0xFF], - string, "", Nullable!byte, 42); - - void test(Cases...)() - { - auto cd = ColumnData(Cases[1]); - assert(cd.as!(Cases[0]) == Cases[1]); - static if (Cases.length > 2) - test!(Cases[2..$])(); - } - - test!AllCases(); -} - -unittest // ColumnData.toString -{ - auto db = Database(":memory:"); - auto rc = db.execute("SELECT 42, 3.14, 'foo_bar', x'00FF', NULL").cached; - assert("%(%s%)".format(rc) == "[42, 3.14, foo_bar, [0, 255], null]"); -} - -unittest // CachedResults copies -{ - auto db = Database(":memory:"); - db.run("CREATE TABLE test (msg TEXT); - INSERT INTO test (msg) VALUES ('ABC')"); - - static getdata(Database db) - { - return db.execute("SELECT * FROM test").cached; - } - - auto data = getdata(db); - assert(data.length == 1); - assert(data[0][0].as!string == "ABC"); -} - -unittest // UTF-8 -{ - auto db = Database(":memory:"); - bool ran = false; - db.run("SELECT '\u2019\u2019';", (ResultRange r) { - assert(r.oneValue!string == "\u2019\u2019"); - ran = true; - return true; - }); - assert(ran); -} - -unittest // loadExtension failure test -{ - import std.exception : collectExceptionMsg; - auto db = Database(":memory:"); - auto msg = collectExceptionMsg(db.loadExtension("foobar")); - assert(msg.canFind("(not authorized)")); -} |