Datei search engine test.dart
Zur Navigation springen
Zur Suche springen
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:io
und die externen Paketeargs
,test
undpath
.
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.path
den 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 namensdgrep
ergänzt, so dass inbase
dann unter Linux/tmp/dgrep
und unter Windowsc:\temp\dgrep
steht.writeString(join(base, 'text1.data'), string: '333');
join(base, 'text1.data')
setzt den Dateinamen aus Basisverzeichnis und Namentext1.data
zusammen.writeString
schreibt den String333
in 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\n
einzutragen.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 KlasseSearchEngine
gespeichert werden, setzen wir das statische AttributstoreResult
auftrue
.- 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~!X
oder im Basisverzeichnis liegen, mit der Endung.txt
. Es wird auch in Unterverzeichnissen (--recursive
) gesucht. Das erste Dateisuchmuster*.y~!X
ist 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.storeResult
gesetzt 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 Methodeexecute
muss dann <code<null sein. *engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']);
Wir verwenden eine unbekannte Option--none-known
. Wieder muss das Ergebnisnull
sein, was mit der KonstanteisNull
festgelegt wird. *engine = SearchEngine.execute([]);
Keine Argumente anzugeben ist ebenfalls ein Fehler, der als Ergebnisnull
liefern muss.