From 51e62d4e2f6278674bc6552442e431fe2fd8e639 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sun, 22 Nov 2020 17:40:53 +0100 Subject: [PATCH] Run tests with null assertions enabled --- .github/workflows/main.yml | 2 +- moor/CHANGELOG.md | 4 +- .../statements/select/select.dart | 2 +- moor/test/columns/datetime_test.dart | 11 ++-- moor/test/columns/int_column_test.dart | 4 +- moor/test/data/tables/todos.dart | 4 +- moor/test/data/utils/mocks.dart | 2 +- moor/test/data/utils/null_executor.dart | 51 +++++++++++++++++++ moor/test/data_class_test.dart | 8 +-- .../test/engines/delegated_database_test.dart | 25 ++++----- moor/test/expressions/comparable_test.dart | 11 ++-- moor/test/expressions/constant_test.dart | 2 +- .../expressions/datetime_expression_test.dart | 2 +- moor/test/expressions/in_expression_test.dart | 6 +-- moor/test/expressions/null_check_test.dart | 5 +- moor/test/expressions/text_test.dart | 5 +- moor/test/expressions/variable_test.dart | 6 +-- .../extensions/moor_ffi_functions_test.dart | 17 +++---- moor/test/legacy_test.dart | 32 ------------ moor/test/utils/lazy_database_test.dart | 5 +- 20 files changed, 110 insertions(+), 94 deletions(-) create mode 100644 moor/test/data/utils/null_executor.dart delete mode 100644 moor/test/legacy_test.dart diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 778938ec..c0381204 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: # build, test and upload coverage - run: dart run build_runner build --delete-conflicting-outputs working-directory: moor - - run: dart --no-sound-null-safety test #-x background_isolate --coverage=coverage + - run: dart --no-sound-null-safety --null-assertions test #-x background_isolate --coverage=coverage working-directory: moor # - uses: actions/upload-artifact@v2 # with: diff --git a/moor/CHANGELOG.md b/moor/CHANGELOG.md index ad595bda..f379bfc6 100644 --- a/moor/CHANGELOG.md +++ b/moor/CHANGELOG.md @@ -1,5 +1,7 @@ -## unreleased +## unreleased (breaking - 4.0) +- __Breaking__: Removed the second type parameter from `TypedResult.read` +- Support null safety - Changed the sql representation of text types from `VARCHAR` to `TEXT` - Added extensions for `isNull` and `isNotNull` - Support creating a `VmDatabase` from a raw sqlite3 `Database` via `VmDatabase.opened` diff --git a/moor/lib/src/runtime/query_builder/statements/select/select.dart b/moor/lib/src/runtime/query_builder/statements/select/select.dart index eb0d2674..0fc53246 100644 --- a/moor/lib/src/runtime/query_builder/statements/select/select.dart +++ b/moor/lib/src/runtime/query_builder/statements/select/select.dart @@ -143,7 +143,7 @@ class TypedResult { /// as a column, for instance via [JoinedSelectStatement.addColumns]. /// /// To access the underlying columns directly, use [rawData]. - D? read>(Expression expr) { + D? read(Expression expr) { if (_parsedExpressions != null) { return _parsedExpressions![expr] as D; } diff --git a/moor/test/columns/datetime_test.dart b/moor/test/columns/datetime_test.dart index 89502ed8..98e33d01 100644 --- a/moor/test/columns/datetime_test.dart +++ b/moor/test/columns/datetime_test.dart @@ -1,14 +1,13 @@ -//@dart=2.9 import 'package:moor/moor.dart'; import 'package:test/test.dart'; void main() { - final nullable = GeneratedDateTimeColumn('name', null, true); - final nonNull = GeneratedDateTimeColumn('name', null, false); + final nullable = GeneratedDateTimeColumn('name', 'table', true); + final nonNull = GeneratedDateTimeColumn('name', 'table', false); test('should write column definition', () { - final nonNullQuery = GenerationContext(null, null); - final nullableQuery = GenerationContext(null, null); + final nonNullQuery = GenerationContext.fromDb(null); + final nullableQuery = GenerationContext.fromDb(null); nonNull.writeColumnDefinition(nonNullQuery); nullable.writeColumnDefinition(nullableQuery); @@ -17,7 +16,7 @@ void main() { }); test('can compare', () { - final ctx = GenerationContext(null, null); + final ctx = GenerationContext.fromDb(null); nonNull.isSmallerThan(currentDateAndTime).writeInto(ctx); expect(ctx.sql, "name < strftime('%s', CURRENT_TIMESTAMP)"); diff --git a/moor/test/columns/int_column_test.dart b/moor/test/columns/int_column_test.dart index 473c2de4..9f19267f 100644 --- a/moor/test/columns/int_column_test.dart +++ b/moor/test/columns/int_column_test.dart @@ -14,7 +14,7 @@ void main() { hasAutoIncrement: true, ); - final context = GenerationContext.fromDb(TodoDb(null)); + final context = GenerationContext.fromDb(TodoDb()); column.writeColumnDefinition(context); expect( @@ -30,7 +30,7 @@ void main() { hasAutoIncrement: false, ); - final context = GenerationContext.fromDb(TodoDb(null)); + final context = GenerationContext.fromDb(TodoDb()); column.writeColumnDefinition(context); expect(context.sql, equals('foo INTEGER NOT NULL PRIMARY KEY')); diff --git a/moor/test/data/tables/todos.dart b/moor/test/data/tables/todos.dart index 876ddffa..05e100ff 100644 --- a/moor/test/data/tables/todos.dart +++ b/moor/test/data/tables/todos.dart @@ -2,6 +2,8 @@ import 'package:moor/moor.dart'; // ignore: import_of_legacy_library_into_null_safe import 'package:uuid/uuid.dart'; +import '../utils/null_executor.dart'; + part 'todos.g.dart'; mixin AutoIncrement on Table { @@ -112,7 +114,7 @@ class CustomConverter extends TypeConverter { }, ) class TodoDb extends _$TodoDb { - TodoDb(QueryExecutor e) : super(e) { + TodoDb([QueryExecutor? e]) : super(e ?? const NullExecutor()) { moorRuntimeOptions.dontWarnAboutMultipleDatabases = true; } TodoDb.connect(DatabaseConnection connection) : super.connect(connection) { diff --git a/moor/test/data/utils/mocks.dart b/moor/test/data/utils/mocks.dart index 751665ac..719fd98f 100644 --- a/moor/test/data/utils/mocks.dart +++ b/moor/test/data/utils/mocks.dart @@ -87,7 +87,7 @@ class MockTransactionExecutor extends MockTransactionsInternal { when(runInsert(any, any)).thenAnswer((_) => Future.value(0)); when(runCustom(any, any)).thenAnswer((_) => Future.value()); when(runBatched(any)).thenAnswer((_) => Future.value()); - when(ensureOpen(any)).thenAnswer((_) => Future.value()); + when(ensureOpen(any)).thenAnswer((_) => Future.value(true)); when(send()).thenAnswer((_) => Future.value(null)); when(rollback()).thenAnswer((_) => Future.value(null)); diff --git a/moor/test/data/utils/null_executor.dart b/moor/test/data/utils/null_executor.dart new file mode 100644 index 00000000..ff5de87f --- /dev/null +++ b/moor/test/data/utils/null_executor.dart @@ -0,0 +1,51 @@ +import 'package:moor/backends.dart'; + +class NullExecutor implements QueryExecutor { + const NullExecutor(); + + @override + TransactionExecutor beginTransaction() { + throw UnsupportedError('beginTransaction'); + } + + @override + Future ensureOpen(QueryExecutorUser user) { + throw UnsupportedError('ensureOpen'); + } + + @override + Future runBatched(BatchedStatements statements) { + throw UnsupportedError('runBatched'); + } + + @override + Future runCustom(String statement, [List? args]) { + throw UnsupportedError('runCustom'); + } + + @override + Future runDelete(String statement, List args) { + throw UnsupportedError('runDelete'); + } + + @override + Future runInsert(String statement, List args) { + throw UnsupportedError('runInsert'); + } + + @override + Future>> runSelect(String statement, List args) { + throw UnsupportedError('runSelect'); + } + + @override + Future runUpdate(String statement, List args) { + throw UnsupportedError('runUpdate'); + } + + @override + Future close() => Future.value(); + + @override + SqlDialect get dialect => SqlDialect.sqlite; +} diff --git a/moor/test/data_class_test.dart b/moor/test/data_class_test.dart index 3cff453f..6d94e863 100644 --- a/moor/test/data_class_test.dart +++ b/moor/test/data_class_test.dart @@ -20,13 +20,9 @@ void main() { }); test('can deserialize ints as doubles', () { - final entry = TableWithoutPKData.fromJson({ - 'notReallyAnId': 3, - 'someFloat': 4, - }); + const serializer = ValueSerializer.defaults(); - expect(entry, - TableWithoutPKData(notReallyAnId: 3, someFloat: 4, custom: null)); + expect(serializer.fromJson(3), 3.0); }); test('default serializer can be overridden globally', () { diff --git a/moor/test/engines/delegated_database_test.dart b/moor/test/engines/delegated_database_test.dart index 2a306ea9..2845de01 100644 --- a/moor/test/engines/delegated_database_test.dart +++ b/moor/test/engines/delegated_database_test.dart @@ -43,19 +43,20 @@ void main() { final db = DelegatedDatabase(delegate, isSequential: sequential); await db.ensureOpen(_FakeExecutorUser()); - expect(await db.runSelect(null, null), isEmpty); - expect(await db.runUpdate(null, null), 3); - expect(await db.runInsert(null, null), 4); - await db.runCustom(null); - await db.runBatched(null); + expect(await db.runSelect('select', const []), isEmpty); + expect(await db.runUpdate('update', const []), 3); + expect(await db.runInsert('insert', const []), 4); + await db.runCustom('custom'); + final batched = BatchedStatements([], []); + await db.runBatched(batched); verifyInOrder([ delegate.isOpen, - delegate.runSelect(null, null), - delegate.runUpdate(null, null), - delegate.runInsert(null, null), - delegate.runCustom(null, []), - delegate.runBatched(null), + delegate.runSelect('select', const []), + delegate.runUpdate('update', const []), + delegate.runInsert('insert', const []), + delegate.runCustom('custom', const []), + delegate.runBatched(batched), ]); }); } @@ -150,12 +151,12 @@ void main() { final transaction = db.beginTransaction(); await transaction.ensureOpen(_FakeExecutorUser()); - await transaction.runSelect(null, null); + await transaction.runSelect('SELECT 1;', const []); await transaction.send(); verifyInOrder([ delegate.runCustom('BEGIN TRANSACTION', []), - delegate.runSelect(null, null), + delegate.runSelect('SELECT 1;', const []), delegate.runCustom('COMMIT TRANSACTION', []), ]); }); diff --git a/moor/test/expressions/comparable_test.dart b/moor/test/expressions/comparable_test.dart index 44dc2f73..7ebbd2a6 100644 --- a/moor/test/expressions/comparable_test.dart +++ b/moor/test/expressions/comparable_test.dart @@ -1,4 +1,3 @@ -//@dart=2.9 import 'package:moor/moor.dart'; import 'package:test/test.dart'; @@ -6,8 +5,8 @@ import '../data/tables/todos.dart'; import '../data/utils/expect_equality.dart'; void main() { - final expression = GeneratedIntColumn('col', null, false); - final db = TodoDb(null); + final expression = GeneratedIntColumn('col', 'table', false); + final db = TodoDb(); final comparisons = { expression.isSmallerThan: '<', @@ -24,7 +23,7 @@ void main() { }; group('can compare with other expressions', () { - final compare = GeneratedIntColumn('compare', null, false); + final compare = GeneratedIntColumn('compare', 'table', false); comparisons.forEach((fn, value) { test('for operator $value', () { @@ -54,8 +53,8 @@ void main() { group('between', () { test('other expressions', () { - final low = GeneratedIntColumn('low', null, false); - final high = GeneratedIntColumn('high', null, false); + final low = GeneratedIntColumn('low', 'table', false); + final high = GeneratedIntColumn('high', 'table', false); final ctx = GenerationContext.fromDb(db); expression.isBetween(low, high).writeInto(ctx); diff --git a/moor/test/expressions/constant_test.dart b/moor/test/expressions/constant_test.dart index 96141677..07cff1c7 100644 --- a/moor/test/expressions/constant_test.dart +++ b/moor/test/expressions/constant_test.dart @@ -32,7 +32,7 @@ void main() { } void testStringMapping(String dart, String expectedLiteral) { - final ctx = GenerationContext.fromDb(TodoDb(null)); + final ctx = GenerationContext.fromDb(TodoDb()); final constant = Constant(dart); constant.writeInto(ctx); diff --git a/moor/test/expressions/datetime_expression_test.dart b/moor/test/expressions/datetime_expression_test.dart index 8086cf5b..c7f6aed5 100644 --- a/moor/test/expressions/datetime_expression_test.dart +++ b/moor/test/expressions/datetime_expression_test.dart @@ -8,7 +8,7 @@ import '../data/utils/expect_generated.dart'; typedef _Extractor = Expression Function(Expression d); void main() { - final column = GeneratedDateTimeColumn('val', null, false); + final column = GeneratedDateTimeColumn('val', 'table', false); group('extracting information via top-level method', () { final expectedResults = <_Extractor, String>{ diff --git a/moor/test/expressions/in_expression_test.dart b/moor/test/expressions/in_expression_test.dart index c880a6b7..02f39b76 100644 --- a/moor/test/expressions/in_expression_test.dart +++ b/moor/test/expressions/in_expression_test.dart @@ -7,10 +7,10 @@ import '../data/utils/expect_generated.dart'; void main() { test('in expressions are generated', () { - final innerExpression = GeneratedTextColumn('name', null, true); + final innerExpression = GeneratedTextColumn('name', 'table', true); final isInExpression = innerExpression.isIn(['Max', 'Tobias']); - final context = GenerationContext.fromDb(TodoDb(null)); + final context = GenerationContext.fromDb(TodoDb()); isInExpression.writeInto(context); expect(context.sql, 'name IN (?, ?)'); @@ -18,7 +18,7 @@ void main() { }); test('not in expressions are generated', () { - final innerExpression = GeneratedTextColumn('name', null, true); + final innerExpression = GeneratedTextColumn('name', 'table', true); final isNotIn = innerExpression.isNotIn(['Max', 'Tobias']); expect(isNotIn, generates('name NOT IN (?, ?)', ['Max', 'Tobias'])); diff --git a/moor/test/expressions/null_check_test.dart b/moor/test/expressions/null_check_test.dart index 2b399079..8e516f8f 100644 --- a/moor/test/expressions/null_check_test.dart +++ b/moor/test/expressions/null_check_test.dart @@ -1,4 +1,3 @@ -//@dart=2.9 import 'package:moor/moor.dart'; import 'package:moor/moor.dart' as moor; import 'package:test/test.dart'; @@ -7,7 +6,7 @@ import '../data/utils/expect_equality.dart'; import '../data/utils/expect_generated.dart'; void main() { - final innerExpression = GeneratedTextColumn('name', null, true); + final innerExpression = GeneratedTextColumn('name', 'table', true); test('IS NULL expressions are generated', () { final oldFunction = moor.isNull(innerExpression); @@ -30,7 +29,7 @@ void main() { }); test('generates COALESCE expressions', () { - final expr = moor.coalesce([const Constant(null), const Constant(3)]); + final expr = moor.coalesce([const Constant(null), const Constant(3)]); expect(expr, generates('COALESCE(NULL, 3)')); }); diff --git a/moor/test/expressions/text_test.dart b/moor/test/expressions/text_test.dart index 243d328c..ded9275b 100644 --- a/moor/test/expressions/text_test.dart +++ b/moor/test/expressions/text_test.dart @@ -1,4 +1,3 @@ -//@dart=2.9 import 'package:moor/moor.dart'; import 'package:test/test.dart'; @@ -6,8 +5,8 @@ import '../data/tables/todos.dart'; import '../data/utils/expect_generated.dart'; void main() { - final expression = GeneratedTextColumn('col', null, false); - final db = TodoDb(null); + final expression = GeneratedTextColumn('col', 'table', false); + final db = TodoDb(); test('generates like expressions', () { final ctx = GenerationContext.fromDb(db); diff --git a/moor/test/expressions/variable_test.dart b/moor/test/expressions/variable_test.dart index 5f2cb81f..6ce21633 100644 --- a/moor/test/expressions/variable_test.dart +++ b/moor/test/expressions/variable_test.dart @@ -8,7 +8,7 @@ void main() { test('maps the variable to sql', () { final variable = Variable(DateTime.fromMillisecondsSinceEpoch(1551297563000)); - final ctx = GenerationContext.fromDb(TodoDb(null)); + final ctx = GenerationContext.fromDb(TodoDb()); variable.writeInto(ctx); @@ -17,8 +17,8 @@ void main() { }); test('writes null directly for null values', () { - final variable = Variable.withString(null); - final ctx = GenerationContext.fromDb(TodoDb(null)); + const variable = Variable(null); + final ctx = GenerationContext.fromDb(TodoDb()); variable.writeInto(ctx); diff --git a/moor/test/extensions/moor_ffi_functions_test.dart b/moor/test/extensions/moor_ffi_functions_test.dart index ed358ef7..d59ef650 100644 --- a/moor/test/extensions/moor_ffi_functions_test.dart +++ b/moor/test/extensions/moor_ffi_functions_test.dart @@ -1,4 +1,3 @@ -//@dart=2.9 @TestOn('vm') import 'package:moor/moor.dart'; import 'package:moor/extensions/moor_ffi.dart'; @@ -9,8 +8,8 @@ import '../data/tables/todos.dart'; import '../data/utils/expect_generated.dart'; void main() { - final a = GeneratedRealColumn('a', null, false); - final b = GeneratedRealColumn('b', null, false); + final a = GeneratedRealColumn('a', 'table', false); + final b = GeneratedRealColumn('b', 'table', false); test('pow', () { expect(sqlPow(a, b), generates('pow(a, b)')); @@ -25,7 +24,7 @@ void main() { test('atan', () => expect(sqlAtan(a), generates('atan(a)'))); test('containsCase', () { - final c = GeneratedTextColumn('a', null, false); + final c = GeneratedTextColumn('a', 'table', false); expect(c.containsCase('foo'), generates('moor_contains(a, ?, 0)', ['foo'])); expect( @@ -39,11 +38,11 @@ void main() { // insert exactly one row so that we can evaluate expressions from Dart await db.into(db.pureDefaults).insert(PureDefaultsCompanion.insert()); - Future evaluate(Expression expr) async { + Future evaluate(Expression expr) async { final result = await (db.selectOnly(db.pureDefaults)..addColumns([expr])) .getSingle(); - return result.read(expr); + return result!.read(expr)!; } expect( @@ -59,7 +58,7 @@ void main() { }); group('regexp flags', () { - TodoDb db; + late TodoDb db; setUp(() async { db = TodoDb(VmDatabase.memory()); @@ -69,11 +68,11 @@ void main() { tearDown(() => db.close()); - Future evaluate(Expression expr) async { + Future evaluate(Expression expr) async { final result = await (db.selectOnly(db.pureDefaults)..addColumns([expr])) .getSingle(); - return result.read(expr); + return result!.read(expr)!; } test('multiLine', () { diff --git a/moor/test/legacy_test.dart b/moor/test/legacy_test.dart deleted file mode 100644 index b4a805ba..00000000 --- a/moor/test/legacy_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Tests that wouldn't compile with null safety enabled. -//@dart=2.9 - -import 'package:moor/moor.dart'; -import 'package:test/test.dart'; - -import 'data/tables/todos.dart'; -import 'data/utils/mocks.dart'; - -void main() { - TodoDb db; - MockExecutor executor; - MockStreamQueries streamQueries; - - setUp(() { - executor = MockExecutor(); - streamQueries = MockStreamQueries(); - - final connection = createConnection(executor, streamQueries); - db = TodoDb.connect(connection); - }); - - test("doesn't allow writing null rows", () { - expect( - () { - return db.into(db.todosTable).insert(null); - }, - throwsA(const TypeMatcher().having( - (e) => e.message, 'message', contains('Cannot write null row'))), - ); - }); -} diff --git a/moor/test/utils/lazy_database_test.dart b/moor/test/utils/lazy_database_test.dart index 37b98c21..f7e7d273 100644 --- a/moor/test/utils/lazy_database_test.dart +++ b/moor/test/utils/lazy_database_test.dart @@ -27,7 +27,8 @@ void main() { clearInteractions(inner); lazy.beginTransaction(); - await lazy.runBatched(null); + final batched = BatchedStatements([], []); + await lazy.runBatched(batched); await lazy.runCustom('custom_stmt'); await lazy.runDelete('delete_stmt', [1]); await lazy.runInsert('insert_stmt', [2]); @@ -35,7 +36,7 @@ void main() { await lazy.runUpdate('update_stmt', [4]); verifyInOrder([ - inner.runBatched(null), + inner.runBatched(batched), inner.runCustom('custom_stmt'), inner.runDelete('delete_stmt', [1]), inner.runInsert('insert_stmt', [2]),