drift/drift_dev/test/analysis/resolver/discover_test.dart

275 lines
7.5 KiB
Dart

import 'package:drift_dev/src/analysis/driver/state.dart';
import 'package:drift_dev/src/analysis/resolver/intermediate_state.dart';
import 'package:drift_dev/src/analysis/results/element.dart';
import 'package:test/test.dart';
import '../test_utils.dart';
void main() {
group('drift files', () {
test('finds local elements', () async {
final backend = await TestBackend.inTest({
'a|lib/main.drift': '''
CREATE TABLE foo (bar INTEGER);
CREATE VIEW my_view AS SELECT whatever FROM unknown_table;
''',
});
final uri = Uri.parse('package:a/main.drift');
final state = await backend.driver.findLocalElements(uri);
final discovered = state.discovery;
DriftElementId id(String name) => DriftElementId(uri, name);
expect(state, hasNoErrors);
expect(
discovered,
isA<DiscoveredDriftFile>()
.having((e) => e.imports, 'imports', isEmpty)
.having(
(e) => e.locallyDefinedElements,
'locallyDefinedElements',
[
isA<DiscoveredDriftTable>()
.having((t) => t.ownId, 'ownId', id('foo')),
isA<DiscoveredDriftView>()
.having((v) => v.ownId, 'ownId', id('my_view')),
],
),
);
});
test('reports syntax errors', () async {
final backend = await TestBackend.inTest({
'a|lib/main.drift': '''
CREATE TABLE valid_1 (bar INTEGER);
CREATE TABLE EXISTS syntax_error ();
CREATE TABLE valid_2 (bar INTEGER);
''',
});
final state = await backend.discoverLocalElements('package:a/main.drift');
expect(state.errorsDuringDiscovery, [
isDriftError(contains('Expected a table name')),
]);
// The syntax error should only affect the single statement
expect(
state.discovery,
isA<DiscoveredDriftFile>().having((e) => e.locallyDefinedElements,
'locallyDefinedElements', hasLength(2)));
});
test('warns about duplicate elements', () async {
final backend = await TestBackend.inTest({
'a|lib/main.drift': '''
CREATE TABLE a (id INTEGER);
CREATE VIEW a AS VALUES(1,2,3);
''',
});
final state = await backend.discoverLocalElements('package:a/main.drift');
expect(state.errorsDuringDiscovery, [
isDriftError(contains('already defines an element named `a`')),
]);
final result = state.discovery as DiscoveredDriftFile;
expect(result.locallyDefinedElements, [isA<DiscoveredDriftTable>()]);
});
group('imports', () {
test('are resolved', () async {
final backend = await TestBackend.inTest({
'a|lib/a.drift': "import 'b.drift';",
'a|lib/b.drift': "CREATE TABLE foo (bar INTEGER);",
});
final state = await backend.discoverLocalElements('package:a/a.drift');
expect(state, hasNoErrors);
expect(
state.discovery,
isA<DiscoveredDriftFile>().having(
(e) => e.importDependencies,
'importDependencies',
[(uri: Uri.parse('package:a/b.drift'), transitive: true)],
),
);
expect(
backend.driver.cache.knownFiles[Uri.parse('package:a/b.drift')],
isNull,
reason: 'Discovering local elements should not prepare other files',
);
});
test('can handle circular imports', () async {
final backend = await TestBackend.inTest({
'a|lib/a.drift': "import 'a.drift'; import 'b.drift';",
'a|lib/b.drift': "import 'a.drift';",
});
final state = await backend.discoverLocalElements('package:a/a.drift');
expect(state, hasNoErrors);
});
});
});
group('dart files', () {
test('fails for part files', () async {
final backend = await TestBackend.inTest({
'a|lib/a.dart': '''
part of 'b.dart';
''',
'a|lib/b.dart': '''
part 'a.dart';
''',
});
final uri = Uri.parse('package:a/a.dart');
final state = await backend.driver.findLocalElements(uri);
expect(state, hasNoErrors);
expect(state.discovery, isA<NotADartLibrary>());
});
test('finds tables', () async {
final backend = await TestBackend.inTest({
'a|lib/a.dart': '''
import 'package:drift/drift.dart';
class Users extends Table {
IntColumn get id => integer()();
}
class Groups extends Table {
IntColumn get id => integer()();
String get tableName => 'my_custom_table';
}
''',
});
final uri = Uri.parse('package:a/a.dart');
final state = await backend.driver.findLocalElements(uri);
expect(state, hasNoErrors);
expect(
state.discovery,
isA<DiscoveredDartLibrary>().having(
(e) => e.locallyDefinedElements,
'locallyDefinedElements',
[
isA<DiscoveredDartTable>()
.having((t) => t.ownId, 'ownId', DriftElementId(uri, 'users')),
isA<DiscoveredDartTable>().having((t) => t.ownId, 'ownId',
DriftElementId(uri, 'my_custom_table')),
],
),
);
});
test('ignores abstract tables', () async {
final backend = await TestBackend.inTest({
'a|lib/a.dart': '''
import 'package:drift/drift.dart';
abstract class Users extends Table {
IntColumn get id => integer()();
}
abstract class BaseRelationTable extends Table {
Column<int?> get parentId;
Column<int?> get childId;
@override
Set<Column> get primaryKey => {parentId, childId};
}
''',
});
final uri = Uri.parse('package:a/a.dart');
final state = await backend.driver.findLocalElements(uri);
expect(state, hasNoErrors);
expect(
state.discovery,
isA<DiscoveredDartLibrary>().having(
(e) => e.locallyDefinedElements,
'locallyDefinedElements',
[
isA<DiscoveredDartTable>()
.having((t) => t.ownId, 'ownId', DriftElementId(uri, 'users')),
],
),
);
});
test('table name errors', () async {
final backend = await TestBackend.inTest({
'a|lib/expr.dart': '''
import 'package:drift/drift.dart';
class InvalidExpression extends Table {
String get tableName => 'foo'.toLowerCase();
}
''',
'a|lib/getter.dart': '''
import 'package:drift/drift.dart';
class InvalidGetter extends Table {
String get tableName {
return '';
}
}
''',
});
for (final source in backend.sourceContents.keys) {
final state = await backend.driver.findLocalElements(Uri.parse(source));
expect(
state.errorsDuringDiscovery,
[isDriftError(contains('must directly return a string literal'))],
reason: 'Should report error for $source',
);
}
});
test('warns about duplicate elements', () async {
final backend = await TestBackend.inTest({
'a|lib/a.dart': '''
import 'package:drift/drift.dart';
class A extends Table {
IntColumn get id => integer()();
String get tableName => 'tbl';
}
class B extends Table {
IntColumn get id => integer()();
String get tableName => 'tbl';
}
''',
});
final state =
await backend.driver.findLocalElements(Uri.parse('package:a/a.dart'));
expect(state.errorsDuringDiscovery, [
isDriftError(contains('already defines an element named `tbl`')),
]);
final result = state.discovery as DiscoveredDartLibrary;
expect(result.locallyDefinedElements, [
isA<DiscoveredDartTable>()
.having((e) => e.dartElement.name, 'dartElement.name', 'A')
]);
});
});
}