drift/drift_dev/test/backends/build/build_integration_test.dart

351 lines
8.8 KiB
Dart

import 'package:build/build.dart';
import 'package:build_test/build_test.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
import '../../utils.dart';
void main() {
test('writes entities from imports', () async {
// Regression test for https://github.com/simolus3/drift/issues/2175
final result = await emulateDriftBuild(inputs: {
'a|lib/main.dart': '''
import 'package:drift/drift.dart';
@DriftDatabase(include: {'a.drift'})
class MyDatabase {}
''',
'a|lib/a.drift': '''
import 'b.drift';
CREATE INDEX b_idx /* comment should be stripped */ ON b (foo);
''',
'a|lib/b.drift': 'CREATE TABLE b (foo TEXT);',
});
checkOutputs({
'a|lib/main.drift.dart': decodedMatches(contains(
"late final Index bIdx = Index('b_idx', 'CREATE INDEX b_idx ON b (foo)')")),
}, result.dartOutputs, result);
});
test('warns about errors in imports', () async {
final logger = Logger.detached('build');
final logs = logger.onRecord.map((e) => e.message).toList();
await emulateDriftBuild(
inputs: {
'a|lib/main.dart': '''
import 'package:drift/drift.dart';
@DriftDatabase(include: {'a.drift'})
class MyDatabase {}
''',
'a|lib/a.drift': '''
import 'b.drift';
file_analysis_error(? AS TEXT): SELECT ? IN ?2;
''',
'a|lib/b.drift': '''
CREATE TABLE syntax_error;
CREATE TABLE a (b TEXT);
CREATE INDEX semantic_error ON a (c);
''',
},
logger: logger,
);
expect(
await logs,
[
allOf(contains('Expected opening parenthesis'),
contains('syntax_error;')),
allOf(contains('Unknown column.'), contains('(c);')),
allOf(contains('Cannot use an array variable with an explicit index'),
contains('?2;')),
],
);
});
test('Dart-defined tables are visible in drift files', () async {
final logger = Logger.detached('build');
expect(logger.onRecord, neverEmits(anything));
final result = await emulateDriftBuild(
inputs: {
'a|lib/database.dart': '''
import 'package:drift/drift.dart';
@DataClassName('DFoo')
class FooTable extends Table {
@override
String get tableName => 'foo';
IntColumn get fooId => integer()();
}
@DriftDatabase(include: {'queries.drift'})
class MyDatabase {}
''',
'a|lib/tables.drift': '''
import 'database.dart';
''',
'a|lib/queries.drift': '''
import 'tables.drift';
selectAll: SELECT * FROM foo;
''',
},
logger: logger,
);
checkOutputs({
'a|lib/database.drift.dart': decodedMatches(contains('selectAll')),
}, result.dartOutputs, result);
});
test('can work with existing part files', () async {
final logger = Logger.detached('build');
expect(logger.onRecord, neverEmits(anything));
final result = await emulateDriftBuild(
inputs: {
'a|lib/main.dart': '''
import 'package:drift/drift.dart';
part 'table.dart';
@DriftDatabase(tables: [Users])
class MyDatabase {}
''',
'a|lib/table.dart': '''
part of 'main.dart';
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get name => text()();
}
''',
},
logger: logger,
);
checkOutputs(
{'a|lib/main.drift.dart': decodedMatches(contains('class User'))},
result.dartOutputs,
result,
);
});
test('handles syntax error in source file', () async {
final logger = Logger.detached('build');
expect(
logger.onRecord,
emits(
isA<LogRecord>()
.having((e) => e.message, 'message',
contains('Could not resolve Dart library package:a/main.dart'))
.having(
(e) => e.error, 'error', isA<SyntaxErrorInAssetException>()),
),
);
final result = await emulateDriftBuild(
inputs: {
'a|lib/main.dart': '''
import 'package:drift/drift.dart';
class Users extends Table {
IntColumn id => integer().autoIncrement()();
TextColumn name => text()();
}
@DriftDatabase(tables: [Users])
class MyDatabase {}
''',
},
logger: logger,
);
checkOutputs({}, result.dartOutputs, result);
});
test('generates custom result classes with modular generation', () async {
final logger = Logger.detached('driftBuild');
expect(logger.onRecord, neverEmits(anything));
final result = await emulateDriftBuild(
inputs: {
'a|lib/main.drift': '''
firstQuery AS MyResultClass: SELECT 'foo' AS r1, 1 AS r2;
secondQuery AS MyResultClass: SELECT 'bar' AS r1, 2 AS r2;
''',
},
modularBuild: true,
logger: logger,
);
checkOutputs({
'a|lib/main.drift.dart': decodedMatches(predicate((String generated) {
return 'class MyResultClass'.allMatches(generated).length == 1;
})),
}, result.dartOutputs, result);
});
test('generates imports for query variables with modular generation',
() async {
final result = await emulateDriftBuild(
inputs: {
'a|lib/main.drift': '''
CREATE TABLE my_table (
a INTEGER PRIMARY KEY,
b TEXT,
c BLOB,
d ANY
) STRICT;
q: INSERT INTO my_table (b, c, d) VALUES (?, ?, ?);
''',
},
modularBuild: true,
logger: loggerThat(neverEmits(anything)),
);
checkOutputs({
'a|lib/main.drift.dart': decodedMatches(
allOf(
contains(
'import \'package:drift/drift.dart\' as i0;\n'
'import \'package:a/main.drift.dart\' as i1;\n'
'import \'dart:typed_data\' as i2;\n'
'import \'package:drift/internal/modular.dart\' as i3;\n',
),
contains(
'class MyTableData extends i0.DataClass\n'
' implements i0.Insertable<i1.MyTableData> {\n'
' final int a;\n'
' final String? b;\n'
' final i2.Uint8List? c;\n'
' final i0.DriftAny? d;\n',
),
contains(
' variables: [\n'
' i0.Variable<String>(var1),\n'
' i0.Variable<i2.Uint8List>(var2),\n'
' i0.Variable<i0.DriftAny>(var3)\n'
' ],\n',
),
),
),
}, result.dartOutputs, result);
});
test('supports `MAPPED BY` for columns', () async {
final results = await emulateDriftBuild(
inputs: {
'a|lib/a.drift': '''
import 'converter.dart';
a: SELECT NULLIF(1, 2) MAPPED BY `myConverter()` AS col;
''',
'a|lib/converter.dart': '''
import 'package:drift/drift.dart';
TypeConverter<Object, int> myConverter() => throw 'stub';
''',
},
modularBuild: true,
);
checkOutputs({
'a|lib/a.drift.dart': decodedMatches(contains('''
class ADrift extends i1.ModularAccessor {
ADrift(i0.GeneratedDatabase db) : super(db);
i0.Selectable<Object?> a() {
return customSelect('SELECT NULLIF(1, 2) AS col',
variables: [], readsFrom: {})
.map((i0.QueryRow row) => i0.NullAwareTypeConverter.wrapFromSql(
i2.myConverter(), row.readNullable<int>('col')));
}
}
''')),
}, results.dartOutputs, results);
});
test('generates type converters for views', () async {
final result = await emulateDriftBuild(
inputs: {
'a|lib/a.drift': '''
import 'converter.dart';
CREATE VIEW my_view AS SELECT
CAST(1 AS ENUM(MyEnum)) AS c1,
CAST('bar' AS ENUMNAME(MyEnum)) AS c2,
1 MAPPED BY `myConverter()` AS c3,
NULLIF(1, 2) MAPPED BY `myConverter()` AS c4
;
''',
'a|lib/converter.dart': '''
import 'package:drift/drift.dart';
enum MyEnum {
foo, bar
}
TypeConverter<Object, int> myConverter() => throw UnimplementedError();
''',
},
modularBuild: true,
logger: loggerThat(neverEmits(anything)),
);
checkOutputs(
{
'a|lib/a.drift.dart': decodedMatches(
allOf(
contains(
''''CREATE VIEW my_view AS SELECT CAST(1 AS INT) AS c1, CAST(\\'bar\\' AS TEXT) AS c2, 1 AS c3, NULLIF(1, 2) AS c4';'''),
contains(r'$converterc1 ='),
contains(r'$converterc2 ='),
contains(r'$converterc3 ='),
contains(r'$converterc4 ='),
contains(r'$converterc4n ='),
),
),
},
result.dartOutputs,
result,
);
});
test('supports @create queries in modular generation', () async {
final result = await emulateDriftBuild(
inputs: {
'a|lib/a.drift': '''
CREATE TABLE foo (bar INTEGER PRIMARY KEY);
@create: INSERT INTO foo VALUES (1);
''',
'a|lib/db.dart': r'''
import 'package:drift/drift.dart';
import 'db.drift.dart';
@DriftDatabase(include: {'a.drift'})
class Database extends $Database {}
''',
},
modularBuild: true,
logger: loggerThat(neverEmits(anything)),
);
checkOutputs({
'a|lib/a.drift.dart':
decodedMatches(contains(r'OnCreateQuery get $drift0 => ')),
'a|lib/db.drift.dart': decodedMatches(contains(r'.$drift0];'))
}, result.dartOutputs, result);
});
}