Datei search engine test.dart
Link
[Bearbeiten]Zielsetzung
[Bearbeiten]Die Datei search_engine_test.dart enthält die Unittests der Datei search_engine.dart.
Für jede Funktion aus search_engine.dart existiert mindestens ein Test.
Import
[Bearbeiten]import 'dart:io'; import 'package:dgrep/helper.dart'; import 'package:dgrep/search_engine.dart'; import 'package:path/path.dart'; import 'package:test/test.dart';
import 'package:dgrep/search_engine.dart';Damit kennt der Compiler die Definitionen aus search_engine.dart.- Die anderen Importe betreffen das interne Paket
dart:iound die externen Paketeargs,testundpath.
Die Funktion init()
[Bearbeiten]Unser Unittest braucht Daten, genauer Dateien, die dann durchsucht werden können.
Diese Dateien werden in der Funktion init() erzeugt.
String init() {
final base = join(Directory.systemTemp.path, 'dgrep');
writeString(join(base, 'text1.txt'), string: '''Eine Zeile ohne Zahl.
3 Chinesen mit dem Kontrabass.
Blub
''');
writeString(join(base, 'text1.data'), string: '333');
final file2 = join(base, 'dir1', 'text2.txt');
writeString(file2, string: 'Teil2\nder Rest steht:\nIn Zeile 3, TEIL 3');
final file3 = join(base, 'dir1', 'text3.text');
writeString(file3, string: '''nix1
nix2
toll3
nix4
toll5
nix6
nix7
nix8
toll9
nix10
''');
return base;
}
final base = path.join(Directory.systemTemp.path, 'dgrep');Damit der Test plattformunabhängig ist, also unter Linux und Windows funktioniert, fragen wir mitDirectory.systemTemp.pathden Namen des temporären Verzeichnisses ab, unter Linux ist das '/tmp', unter Windows 'c:\temp' oder ähnliches. Dieses Verzeichnis wird mit der Funktionjoin()mit dem Unterverzeichnis namensdgrepergänzt, so dass inbasedann unter Linux/tmp/dgrepund unter Windowsc:\temp\dgrepsteht.writeString(join(base, 'text1.data'), string: '333');join(base, 'text1.data')setzt den Dateinamen aus Basisverzeichnis und Namentext1.datazusammen.writeStringschreibt den String333in diese Datei.
writeString(file3, string: ...Hier wird ein mehrzeiliger String benutzt, der mit jeweils drei Appostrophen umrahmt ist. Das gestaltet den Programmtext übersichtlicher als die Zeilentrenner mit dem Metazeichen\neinzutragen.return base;Das Ergebnis der Funktion ist das Basisverzeichnis.
Hauptprogramm und erster Test
[Bearbeiten]void main() {
final baseDirectory = init();
final txtFilePattern = join(baseDirectory, '*.txt');
SearchEngine.storeResult = true;
group('search', () {
test('recursive search', () {
final engine = SearchEngine.execute([
r'\d',
'*.y~!X',
txtFilePattern,
'--recursive',
]);
expect(engine.lines.length, 3);
expect(engine.lines[0],
endsWith('text1.txt-2: 3 Chinesen mit dem Kontrabass.'));
expect(engine.lines[1], endsWith('text2.txt-1: Teil2'));
expect(engine.lines[2], endsWith('text2.txt-3: In Zeile 3, TEIL 3'));
});
...
}
- Jeder Unittest ist ein normales Programm, braucht daher eine Funktion
main. SearchEngine.storeResult = true;Damit die Suchergebnisse in der KlasseSearchEnginegespeichert werden, setzen wir das statische AttributstoreResultauftrue.- Die Tests können mittels der Funktion
group()gruppiert werden, das steigert die Übersicht. test('recursive search', () { ... });Der eigentliche Test findet in der Callbackfunktion (dem zweiten Parameter) der Funktiontest()statt.final engine = SearchEngine.execute([r'\d', ...]);- Der Aufruf der statischen Methode
execute()bekommt die Simulation der Programmargumente übergeben. - Dies entspricht dem Aufruf in der Eingabeaufforderung:
dgrep \d *.y~!X c:\temp\dgrep\*.txt --recursive- oder in Linux:
dgrep '\d' '*.y~!X' '/tmp/dgrep/*.txt' --recursive
- Der Aufruf der statischen Methode
- Wir suchen also eine Dezimalziffer (als regulärer Ausdruck:
\d) in den Dateien, die im aktuellen Verzeichnis liegen und die Endung.y~!Xoder im Basisverzeichnis liegen, mit der Endung.txt. Es wird auch in Unterverzeichnissen (--recursive) gesucht. Das erste Dateisuchmuster*.y~!Xist so gewählt, dass damit keine Dateien gefunden werden, aber normalerweise etliche Unterverzeichnisse durchlaufen werden. Wir testen gleichzeitig, ob die Angabe von zwei Dateisuchmustern funktioniert. - Die Funktion
expect()hat als ersten Parameter den zu testenden Wert, als zweiten den erwarteten Wert. expect(engine.lines.length, 3);- Da wir oben das Attribut
SearchEngine.storeResultgesetzt haben, landen die Trefferzeilen im Attributlines, das eine Stringliste ist. Wir erwarten also 3 Trefferzeilen.
- Da wir oben das Attribut
expect(engine.lines[0], endsWith('text1.txt-2: 3 Chinesen mit dem Kontrabass.'));- Die Trefferzeile beginnt mit dem vollen Dateinamen, der unter Linux bzw. Windows verschieden ist. Daher prüfen wir nur den Rest der Zeile mit
endsWith().
- Die Trefferzeile beginnt mit dem vollen Dateinamen, der unter Linux bzw. Windows verschieden ist. Daher prüfen wir nur den Rest der Zeile mit
- Analog werden die zwei anderen Zeilen getestet.
Die weiteren Tests
[Bearbeiten]- Die weiteren Tests laufen nach dem gleichem Schema wie der erste Test ab.
- Jeder Test prüft die Funktion einer Option bzw. die Kombination von Optionen.
Die Gruppe 'errors'
[Bearbeiten]Die zweite Gruppe ist mit 'errors' als Beschreibung gekennzeichnet: Sie prüft die Fehlersituationen:
group('errors', () {
test('wrong pattern', () {
final engine = SearchEngine.execute([r'*', '.']);
expect(engine.lines.length, 0);
});
test('unknown option', () {
final engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']);
expect(engine, isNull);
});
test('to few arguments', () {
final engine = SearchEngine.execute([]);
expect(engine, isNull);
});
});
* engine = SearchEngine.execute([r'*', '.']); Hier ist ein unzulässiger regulärer Ausdruck als Textsuchmuster angegeben: * ist nicht erlaubt, vor dem Stern muss ein Zeichen, eine Zeichenklasse oder eine Klammer stehen. Das Ergebnis der Methode execute muss dann <code<null sein.
* engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']); Wir verwenden eine unbekannte Option --none-known. Wieder muss das Ergebnis null sein, was mit der Konstante isNull festgelegt wird.
* engine = SearchEngine.execute([]); Keine Argumente anzugeben ist ebenfalls ein Fehler, der als Ergebnis null liefern muss.