mirror of https://github.com/AMT-Cheif/drift.git
91 lines
2.4 KiB
Dart
91 lines
2.4 KiB
Dart
import 'package:collection/collection.dart' show IterableExtension;
|
|
import 'package:source_span/source_span.dart';
|
|
import 'package:sqlparser/sqlparser.dart';
|
|
import 'package:sqlparser/src/utils/ast_equality.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
export 'package:sqlparser/src/reader/tokenizer/token.dart';
|
|
|
|
final defaultSpan = fakeSpan('fake');
|
|
|
|
Token token(TokenType type) {
|
|
return Token(type, defaultSpan);
|
|
}
|
|
|
|
StringLiteralToken stringLiteral(String value) {
|
|
return StringLiteralToken(value, defaultSpan);
|
|
}
|
|
|
|
InlineDartToken inlineDart(String dartCode) {
|
|
return InlineDartToken(fakeSpan('`$dartCode`'));
|
|
}
|
|
|
|
IdentifierToken identifier(String content) {
|
|
return IdentifierToken(false, fakeSpan(content));
|
|
}
|
|
|
|
DriftFile parseDrift(String content) {
|
|
return SqlEngine(EngineOptions(driftOptions: const DriftSqlOptions()))
|
|
.parseDriftFile(content)
|
|
.rootNode as DriftFile;
|
|
}
|
|
|
|
void testDriftFile(String driftFile, DriftFile expected) {
|
|
final parsed = parseDrift(driftFile);
|
|
enforceHasSpan(parsed);
|
|
enforceEqual(parsed, expected);
|
|
}
|
|
|
|
void testStatement(String sql, AstNode expected, {bool driftMode = false}) {
|
|
final result = SqlEngine(EngineOptions(
|
|
driftOptions: driftMode ? const DriftSqlOptions() : null))
|
|
.parse(sql);
|
|
expect(result.errors, isEmpty);
|
|
|
|
final parsed = result.rootNode;
|
|
enforceHasSpan(parsed);
|
|
enforceEqual(parsed, expected);
|
|
}
|
|
|
|
void expectParseError(
|
|
String sql, {
|
|
dynamic message = anything,
|
|
dynamic span = anything,
|
|
}) {
|
|
final result = SqlEngine().parse(sql);
|
|
|
|
expect(result.errors, [isParsingError(message: message, span: span)]);
|
|
}
|
|
|
|
TypeMatcher<ParsingError> isParsingError({
|
|
dynamic message = anything,
|
|
dynamic span = anything,
|
|
}) {
|
|
return isA<ParsingError>()
|
|
.having((e) => e.message, 'message', wrapMatcher(message))
|
|
.having((e) => e.token.span.text, 'span', wrapMatcher(span));
|
|
}
|
|
|
|
FileSpan fakeSpan(String content) {
|
|
return SourceFile.fromString(content).span(0);
|
|
}
|
|
|
|
void testAll(Map<String, AstNode> testCases) {
|
|
testCases.forEach((sql, expected) {
|
|
test('with $sql', () {
|
|
testStatement(sql, expected);
|
|
});
|
|
});
|
|
}
|
|
|
|
/// The parser should make sure [AstNode.hasSpan] is true on relevant nodes.
|
|
void enforceHasSpan(AstNode node) {
|
|
final problematic = [node]
|
|
.followedBy(node.allDescendants)
|
|
.firstWhereOrNull((node) => !node.hasSpan && !node.synthetic);
|
|
|
|
if (problematic != null) {
|
|
throw ArgumentError('Node $problematic did not have a span');
|
|
}
|
|
}
|