Add more tests in moor_ffi subproject

This commit is contained in:
Simon Binder 2019-09-22 16:26:17 +02:00
parent 0d56594933
commit b99bc820da
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
9 changed files with 125 additions and 14 deletions

View File

@ -96,7 +96,9 @@ dev_dependencies:
In the file where you created a `FlutterQueryExecutor`, replace the `moor_flutter` import
with both `package:moor/moor.dart` and `package:moor_ffi/moor_ffi.dart`.
In all other project files that use moor apis (e.g. a `Value` class for companions), just import `package:moor/moor.dart`.
Finally, replace usages of `FlutterQueryExecutor` with `VmDatabase`.
Finally, replace usages of `FlutterQueryExecutor` with `VmDatabase`.
Note that, at the moment, there is no counterpart for `FlutterQueryExecutor.inDatabasePath` and that the async API using
a background isolate is not available yet. Both shortcomings with be fixed by the upcoming moor 2.0 release.

View File

@ -44,6 +44,7 @@ class Database implements BaseDatabase {
if (resultCode == Errors.SQLITE_OK) {
return Database._(dbPointer);
} else {
bindings.sqlite3_close_v2(dbPointer);
throw SqliteException._fromErrorCode(dbPointer, resultCode);
}
}
@ -56,6 +57,12 @@ class Database implements BaseDatabase {
@override
void close() {
// close all prepared statements first
_isClosed = true;
for (var stmt in _preparedStmt) {
stmt.close();
}
final code = bindings.sqlite3_close_v2(_db);
SqliteException exception;
if (code != Errors.SQLITE_OK) {
@ -63,10 +70,7 @@ class Database implements BaseDatabase {
}
_isClosed = true;
for (var stmt in _preparedStmt) {
stmt.close();
}
_db.free();
// we don't need to deallocate the _db pointer, sqlite takes care of that
if (exception != null) {
throw exception;
@ -82,6 +86,7 @@ class Database implements BaseDatabase {
@override
void execute(String sql) {
_ensureOpen();
final sqlPtr = CBlob.allocateString(sql);
final errorOut = Pointer<Pointer<CBlob>>.allocate();
@ -125,7 +130,10 @@ class Database implements BaseDatabase {
throw SqliteException._fromErrorCode(_db, resultCode);
}
return PreparedStatement._(stmt, this);
final prepared = PreparedStatement._(stmt, this);
_preparedStmt.add(prepared);
return prepared;
}
@override

View File

@ -48,6 +48,8 @@ class DbOperationProxy {
final SendPort send;
final Isolate isolate;
var closed = false;
int _currentRequestId = 0;
DbOperationProxy(
@ -57,6 +59,10 @@ class DbOperationProxy {
Future<dynamic> sendRequest(IsolateCommandType type, dynamic data,
{int preparedStmtId}) {
if (closed) {
throw StateError('Tried to call a database method after .close()');
}
final id = _currentRequestId++;
final cmd = IsolateCommand(id, type, data)
..preparedStatementId = preparedStmtId;
@ -80,6 +86,7 @@ class DbOperationProxy {
}
void close() {
closed = true;
_receivePort.close();
backgroundMsgs.close();
isolate.kill();
@ -128,7 +135,15 @@ class BackgroundIsolateRunner {
final response = _handleCommand(data);
send.send(IsolateResponse(data.requestId, response, null));
} catch (e) {
send.send(IsolateResponse(data.requestId, null, e));
if (e is Error) {
// errors contain a StackTrace, which cannot be sent. So we just
// send the description of that stacktrace.
final exception =
Exception('Error in background isolate: $e\n${e.stackTrace}');
send.send(IsolateResponse(data.requestId, null, exception));
} else {
send.send(IsolateResponse(data.requestId, null, e));
}
}
}
});

View File

@ -22,7 +22,7 @@ class PreparedStatement implements BasePreparedStatement {
void _ensureNotFinalized() {
if (_closed) {
throw Exception('Tried to operate on a released prepared statement');
throw StateError('Tried to operate on a released prepared statement');
}
}

View File

@ -1,16 +1,15 @@
name: moor_ffi
description: "Experimental moor implementation that uses dart:ffi"
description: "Experimental sqlite bindings using dart:ffi"
version: 0.0.1
author:
homepage:
author: Simon Binder <oss@simonbinder.eu>
homepage: https://github.com/simolus3/moor/tree/develop/moor_ffi
issue_tracker: https://github.com/simolus3/moor/issues
environment:
sdk: ">=2.5.0-dev <2.6.0"
dependencies:
moor: ">=1.7.0 <2.1.0"
# flutter:
# sdk: flutter
dev_dependencies:
test: ^1.6.0

View File

@ -0,0 +1,21 @@
import 'package:moor/moor.dart';
import 'package:moor_ffi/src/ffi/blob.dart';
import 'package:test/test.dart';
void main() {
test('utf8 store and load test', () {
final content = 'Hasta Mañana';
final blob = CBlob.allocateString(content);
expect(blob.load<CBlob>().readString(), content);
blob.free();
});
test('blob load and store test', () {
final data = List.generate(256, (x) => x);
final blob = CBlob.allocate(Uint8List.fromList(data));
expect(blob.load<CBlob>().read(256), data);
blob.free();
});
}

View File

@ -5,6 +5,8 @@ import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:moor_ffi/database.dart';
import 'suite/insert.dart' as insert;
import 'suite/prepared_statements.dart' as prepared_statements;
import 'suite/select.dart' as select;
import 'suite/user_version.dart' as user_version;
@ -59,6 +61,8 @@ void main() {
}
void _declareAll(TestedDatabase db) {
insert.main(db);
prepared_statements.main(db);
select.main(db);
user_version.main(db);
}

View File

@ -0,0 +1,18 @@
import 'package:test/test.dart';
import '../runners.dart';
void main(TestedDatabase db) {
test('insert statements report their id', () async {
final opened = await db.openMemory();
await opened
.execute('CREATE TABLE tbl(a INTEGER PRIMARY KEY AUTOINCREMENT)');
for (var i = 0; i < 5; i++) {
await opened.execute('INSERT INTO tbl DEFAULT VALUES');
expect(await opened.getLastInsertId(), i + 1);
}
await opened.close();
});
}

View File

@ -0,0 +1,44 @@
import 'package:test/test.dart';
import '../runners.dart';
void main(TestedDatabase db) {
test('prepared statements can be used multiple times', () async {
final opened = await db.openMemory();
await opened.execute('CREATE TABLE tbl (a TEXT);');
final stmt = await opened.prepare('INSERT INTO tbl(a) VALUES(?)');
await stmt.execute(['a']);
await stmt.execute(['b']);
await stmt.close();
final select = await opened.prepare('SELECT * FROM tbl ORDER BY a');
final result = await select.select();
expect(result, hasLength(2));
expect(result.map((row) => row['a']), ['a', 'b']);
await select.close();
await opened.close();
});
test('prepared statements cannot be used after close', () async {
final opened = await db.openMemory();
final stmt = await opened.prepare('SELECT ?');
await stmt.close();
expect(stmt.select, throwsA(anything));
await opened.close();
});
test('prepared statements cannot be used after db is closed', () async {
final opened = await db.openMemory();
final stmt = await opened.prepare('SELECT 1');
await opened.close();
expect(stmt.select, throwsA(anything));
});
}