Improve test coverage for query generation

This commit is contained in:
Simon Binder 2019-11-12 21:16:48 +01:00
parent 85fa0d4764
commit bea001bb16
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
11 changed files with 189 additions and 13 deletions

View File

@ -5,4 +5,5 @@ targets:
options:
override_hash_and_equals_in_result_sets: true
use_column_name_as_json_key_when_defined_in_moor_file: true
generate_connect_constructor: true
generate_connect_constructor: true
write_from_json_string_constructor: true

View File

@ -29,6 +29,11 @@ class Category extends DataClass implements Insertable<Category> {
description: serializer.fromJson<String>(json['description']),
);
}
factory Category.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
Category.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -204,6 +209,10 @@ class Recipe extends DataClass implements Insertable<Recipe> {
category: serializer.fromJson<int>(json['category']),
);
}
factory Recipe.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
Recipe.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -438,6 +447,11 @@ class Ingredient extends DataClass implements Insertable<Ingredient> {
caloriesPer100g: serializer.fromJson<int>(json['caloriesPer100g']),
);
}
factory Ingredient.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
Ingredient.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -644,6 +658,11 @@ class IngredientInRecipe extends DataClass
amountInGrams: serializer.fromJson<int>(json['amountInGrams']),
);
}
factory IngredientInRecipe.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
IngredientInRecipe.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {

View File

@ -6,7 +6,7 @@ part of '../query_builder.dart';
Expression<bool, BoolType> isIn<X extends SqlType<T>, T>(
Expression<T, X> expression, Iterable<T> values,
{bool not = false}) {
if (not == false) {
if (not == true) {
return expression.isNotIn(values);
} else {
return expression.isIn(values);

View File

@ -25,6 +25,10 @@ class NoId extends DataClass implements Insertable<NoId> {
payload: serializer.fromJson<Uint8List>(json['payload']),
);
}
factory NoId.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
NoId.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -156,6 +160,11 @@ class WithDefault extends DataClass implements Insertable<WithDefault> {
b: serializer.fromJson<int>(json['b']),
);
}
factory WithDefault.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
WithDefault.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -315,6 +324,11 @@ class WithConstraint extends DataClass implements Insertable<WithConstraint> {
c: serializer.fromJson<double>(json['c']),
);
}
factory WithConstraint.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
WithConstraint.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -499,6 +513,10 @@ class Config extends DataClass implements Insertable<Config> {
configValue: serializer.fromJson<String>(json['config_value']),
);
}
factory Config.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
Config.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -674,6 +692,11 @@ class MytableData extends DataClass implements Insertable<MytableData> {
somedate: serializer.fromJson<DateTime>(json['somedate']),
);
}
factory MytableData.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
MytableData.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {

View File

@ -47,6 +47,11 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
category: serializer.fromJson<int>(json['category']),
);
}
factory TodoEntry.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
TodoEntry.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -318,6 +323,11 @@ class Category extends DataClass implements Insertable<Category> {
description: serializer.fromJson<String>(json['description']),
);
}
factory Category.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
Category.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -497,6 +507,10 @@ class User extends DataClass implements Insertable<User> {
creationTime: serializer.fromJson<DateTime>(json['creationTime']),
);
}
factory User.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
User.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -768,6 +782,11 @@ class SharedTodo extends DataClass implements Insertable<SharedTodo> {
user: serializer.fromJson<int>(json['user']),
);
}
factory SharedTodo.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
SharedTodo.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -943,6 +962,11 @@ class TableWithoutPKData extends DataClass
custom: serializer.fromJson<MyCustomObject>(json['custom']),
);
}
factory TableWithoutPKData.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
TableWithoutPKData.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
@ -1151,6 +1175,11 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
txt: serializer.fromJson<String>(json['txt']),
);
}
factory PureDefault.fromJsonString(String encodedJson,
{ValueSerializer serializer = const ValueSerializer.defaults()}) =>
PureDefault.fromJson(
DataClass.parseJson(encodedJson) as Map<String, dynamic>,
serializer: serializer);
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {

View File

@ -0,0 +1,19 @@
import 'package:test/test.dart';
import 'data/tables/todos.dart';
void main() {
test('data classes can be serialized', () {
final entry = TodoEntry(
id: 13,
title: 'Title',
content: 'Content',
targetDate: DateTime.now(),
);
final serialized = entry.toJsonString();
final deserialized = TodoEntry.fromJsonString(serialized);
expect(deserialized, equals(deserialized));
});
}

View File

@ -1,6 +1,7 @@
import 'package:test/test.dart';
import 'package:moor/moor.dart';
import 'data/tables/todos.dart';
import 'data/utils/mocks.dart';
class _FakeDb extends GeneratedDatabase {
@ -66,4 +67,22 @@ void main() {
verify(executor.runSelect('opened: 3 to 4', []));
});
});
test('creates and attaches daos', () async {
final executor = MockExecutor();
final db = TodoDb(executor);
await db.someDao.todosForUser(1);
verify(executor.runSelect(argThat(contains('SELECT t.* FROM todos')), [1]));
});
test('closing the database closes the executor', () async {
final executor = MockExecutor();
final db = TodoDb(executor);
await db.close();
verify(executor.close());
});
}

View File

@ -1,7 +1,7 @@
import 'package:moor/moor.dart';
import 'package:test/test.dart';
import '../data/tables/todos.dart';
import '../data/utils/expect_generated.dart';
void main() {
final i1 = GeneratedIntColumn('i1', 'tbl', true);
@ -10,18 +10,15 @@ void main() {
final s2 = GeneratedTextColumn('s2', 'tbl', true);
test('arithmetic test', () {
_expectSql(i1 + i2 * i1, 'i1 + i2 * i1');
_expectSql((i1 + i2) * i1, '(i1 + i2) * i1');
(i1 + i2 * i1).expectGenerates('i1 + i2 * i1');
(i1 + i2 * i1).expectGenerates('i1 + i2 * i1');
((i1 + i2) * i1).expectGenerates('(i1 + i2) * i1');
(i1 - i2).expectGenerates('i1 - i2');
(i1 - -i2).expectGenerates('i1 - -i2');
(i1 / i2).expectGenerates('i1 / i2');
});
test('string concatenation', () {
_expectSql(s1 + s2, 's1 || s2');
(s1 + s2).expectGenerates('s1 || s2');
});
}
void _expectSql(Expression e, String expected) {
final ctx = GenerationContext.fromDb(TodoDb(null));
e.writeInto(ctx);
expect(ctx.sql, expected);
}

View File

@ -0,0 +1,23 @@
import 'package:moor/moor.dart';
import 'package:test/test.dart';
import '../data/utils/expect_generated.dart';
// ignore_for_file: deprecated_member_use_from_same_package
void main() {
final a = GeneratedBoolColumn('a', 'tbl', false);
final b = GeneratedBoolColumn('b', 'tbl', false);
test('boolean expressions via operators', () {
(a | b).expectGenerates('a OR b');
(a & b).expectGenerates('a AND b');
a.not().expectGenerates('NOT a');
});
test('boolean expressions via top-level methods', () {
or(a, b).expectGenerates('a OR b');
and(a, b).expectGenerates('a AND b');
not(a).expectGenerates('NOT a');
});
}

View File

@ -0,0 +1,26 @@
import 'package:test/test.dart';
import 'package:moor/moor.dart';
import '../data/utils/expect_generated.dart';
class _UnknownExpr extends Expression {
@override
void writeInto(GenerationContext context) {
context.buffer.write('???');
}
}
void main() {
test('precedence ordering', () {
expect(Precedence.plusMinus < Precedence.mulDivide, isTrue);
expect(Precedence.unary <= Precedence.unary, isTrue);
expect(Precedence.postfix >= Precedence.bitwise, isTrue);
expect(Precedence.postfix > Precedence.primary, isFalse);
});
test('puts parentheses around expressions with unknown precedence', () {
final expr = _UnknownExpr().equalsExp(_UnknownExpr());
expr.expectGenerates('(???) = (???)');
});
}

View File

@ -96,4 +96,24 @@ void main() {
await db.customStatement('some custom statement');
verify(mockExecutor.runCustom('some custom statement'));
});
test('upgrading a database without schema migration throws', () async {
final db = _DefaultDb(MockExecutor());
expect(
() => db.handleDatabaseVersionChange(
executor: MockQueryExecutor(), from: 1, to: 2),
throwsA(const TypeMatcher<Exception>()));
});
}
class _DefaultDb extends GeneratedDatabase {
_DefaultDb(QueryExecutor executor)
// ignore: prefer_const_constructors
: super(SqlTypeSystem.withDefaults(), executor);
@override
List<TableInfo<Table, DataClass>> get allTables => [];
@override
int get schemaVersion => 2;
}