2020-06-02 13:26:59 -07:00
|
|
|
import 'package:analyzer/dart/analysis/features.dart';
|
|
|
|
import 'package:analyzer/dart/analysis/utilities.dart';
|
|
|
|
import 'package:analyzer/dart/ast/ast.dart';
|
|
|
|
import 'package:analyzer/file_system/memory_file_system.dart';
|
|
|
|
import 'package:build/build.dart';
|
|
|
|
import 'package:build_test/build_test.dart';
|
2022-07-03 13:20:24 -07:00
|
|
|
import 'package:drift_dev/src/backends/build/drift_builder.dart';
|
2020-12-12 11:34:01 -08:00
|
|
|
import 'package:pub_semver/pub_semver.dart';
|
2021-09-10 02:43:21 -07:00
|
|
|
import 'package:test/test.dart';
|
2020-06-02 13:26:59 -07:00
|
|
|
|
|
|
|
const _testInput = r'''
|
2021-10-08 13:40:58 -07:00
|
|
|
import 'package:drift/drift.dart';
|
2020-06-02 13:26:59 -07:00
|
|
|
|
|
|
|
part 'main.moor.dart';
|
|
|
|
|
|
|
|
class Users extends Table {
|
|
|
|
IntColumn get id => integer().autoIncrement()();
|
|
|
|
TextColumn get name => text()();
|
|
|
|
}
|
|
|
|
|
2021-10-08 13:40:58 -07:00
|
|
|
@DriftDatabase(
|
2020-06-02 13:26:59 -07:00
|
|
|
tables: [Users],
|
|
|
|
queries: {
|
|
|
|
'someQuery': 'SELECT 1 AS foo, 2 AS bar;',
|
|
|
|
},
|
|
|
|
)
|
|
|
|
class Database extends _$Database {}
|
|
|
|
''';
|
|
|
|
|
|
|
|
void main() {
|
2022-07-01 12:34:02 -07:00
|
|
|
test('generates mutable classes if needed', () async {
|
|
|
|
await testBuilder(
|
2022-07-03 13:20:24 -07:00
|
|
|
DriftPartBuilder(const BuilderOptions({'mutable_classes': true})),
|
2022-07-01 12:34:02 -07:00
|
|
|
const {'a|lib/main.dart': _testInput},
|
|
|
|
reader: await PackageAssetReader.currentIsolate(),
|
|
|
|
outputs: const {
|
|
|
|
'a|lib/main.moor.dart': _GeneratesWithoutFinalFields(
|
|
|
|
{'User', 'UsersCompanion', 'SomeQueryResult'},
|
|
|
|
),
|
|
|
|
},
|
|
|
|
);
|
2020-06-02 13:26:59 -07:00
|
|
|
}, tags: 'analyzer');
|
|
|
|
}
|
|
|
|
|
|
|
|
class _GeneratesWithoutFinalFields extends Matcher {
|
|
|
|
final Set<String> expectedWithoutFinals;
|
|
|
|
|
2022-07-01 12:34:02 -07:00
|
|
|
const _GeneratesWithoutFinalFields(this.expectedWithoutFinals);
|
2020-06-02 13:26:59 -07:00
|
|
|
|
|
|
|
@override
|
|
|
|
Description describe(Description description) {
|
|
|
|
return description.add('generates classes $expectedWithoutFinals without '
|
|
|
|
'final fields.');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
bool matches(dynamic desc, Map matchState) {
|
|
|
|
// Parse the file, assure we don't have final fields in data classes.
|
|
|
|
final resourceProvider = MemoryResourceProvider();
|
|
|
|
if (desc is List<int>) {
|
|
|
|
resourceProvider.newFileWithBytes('/foo.dart', desc);
|
|
|
|
} else if (desc is String) {
|
|
|
|
resourceProvider.newFile('/foo.dart', desc);
|
|
|
|
} else {
|
|
|
|
desc['desc'] = 'Neither a List<int> or String - cannot be parsed';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
final parsed = parseFile(
|
|
|
|
path: '/foo.dart',
|
2020-12-12 11:34:01 -08:00
|
|
|
featureSet: FeatureSet.fromEnableFlags2(
|
2022-07-01 12:34:02 -07:00
|
|
|
sdkLanguageVersion: Version(2, 12, 0),
|
2020-12-12 11:34:01 -08:00
|
|
|
flags: const [],
|
|
|
|
),
|
2020-06-02 13:26:59 -07:00
|
|
|
resourceProvider: resourceProvider,
|
2020-07-17 04:12:06 -07:00
|
|
|
throwIfDiagnostics: true,
|
2020-06-02 13:26:59 -07:00
|
|
|
).unit;
|
|
|
|
|
|
|
|
final remaining = expectedWithoutFinals.toSet();
|
|
|
|
|
|
|
|
final definedClasses = parsed.declarations.whereType<ClassDeclaration>();
|
|
|
|
for (final definedClass in definedClasses) {
|
|
|
|
if (expectedWithoutFinals.contains(definedClass.name.name)) {
|
2020-07-17 04:12:06 -07:00
|
|
|
for (final member in definedClass.members) {
|
|
|
|
if (member is FieldDeclaration) {
|
|
|
|
if (member.fields.isFinal) {
|
|
|
|
matchState['desc'] =
|
|
|
|
'Field ${member.fields.variables.first.name.name} in '
|
|
|
|
'${definedClass.name.name} is final.';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (member is ConstructorDeclaration) {
|
|
|
|
if (member.constKeyword != null) {
|
|
|
|
matchState['desc'] = 'Constructor ${member.name?.name ?? ''} in '
|
|
|
|
'${definedClass.name.name} is constant.';
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-02 13:26:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remaining.remove(definedClass.name.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Also ensure that all expected classes were generated.
|
|
|
|
if (remaining.isNotEmpty) {
|
|
|
|
matchState['desc'] = 'Did not generate $remaining classes';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Description describeMismatch(dynamic item, Description mismatchDescription,
|
|
|
|
Map matchState, bool verbose) {
|
2022-07-01 12:34:02 -07:00
|
|
|
return mismatchDescription
|
|
|
|
.add((matchState['desc'] as String?) ?? 'Had syntax errors');
|
2020-06-02 13:26:59 -07:00
|
|
|
}
|
|
|
|
}
|