From 9397ebaa3703760ee33817d20101e06ba9535391 Mon Sep 17 00:00:00 2001
From: "Erik C. Thauvin"
Date: Sun, 10 Oct 2021 20:23:09 -0700
Subject: [PATCH] Added show non-printing option.
---
README.md | 27 ++--
bin/dcat.dart | 49 +++++-
doc/api/dcat/cat.html | 37 +++--
doc/api/dcat/dcat-library.html | 23 +--
doc/api/dcat/exitFailure-constant.html | 1 -
doc/api/dcat/exitSuccess-constant.html | 1 -
doc/api/dcat/libName-constant.html | 129 ---------------
doc/api/dcat/printError.html | 15 +-
doc/api/index.html | 27 ++--
doc/api/index.json | 2 +-
lib/dcat.dart | 91 ++++++++---
pubspec.yaml | 2 +-
test/dcat_test.dart | 207 +++++++++++++++----------
test/test.txt | 3 +
14 files changed, 316 insertions(+), 298 deletions(-)
delete mode 100644 doc/api/dcat/libName-constant.html
diff --git a/README.md b/README.md
index 1a7036c..280be91 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,10 @@
A **cat** command-line implemenation in [Dart](https://dart.dev/), inspired by the [Write command-line apps sample code](https://dart.dev/tutorials/server/cmdline).
+## Synopsis
+
+**dcat** copies each file, or standard input if none are given, to standard output.
+
## Command-Line Usage
```sh
@@ -16,19 +20,23 @@ Concatenate FILE(s) to standard output.
With no FILE, or when FILE is -, read standard input.
- -b, --number-nonblank number nonempty output lines, overrides -n
- -E, --show-ends display $ at end of each line
- -h, --help display this help and exit
- -n, --number number all output lines
- -T, --show-tabs display TAB characters as ^I
- -s, --squeeze-blank suppress repeated empty output lines
- --version output version information and exit
+ -A, --show-all equivalent to -vET
+ -b, --number-nonblank number nonempty output lines, overrides -n
+ -e, --show-nonprinting-ends equivalent to -vE
+ -E, --show-ends display $ at end of each line
+ -h, --help display this help and exit
+ -n, --number number all output lines
+ -t, --show-nonprinting-tabs equivalent to -vT
+ -T, --show-tabs display TAB characters as ^I
+ -s, --squeeze-blank suppress repeated empty output lines
+ --version output version information and exit
+ -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
Examples:
dcat f - g Output f's contents, then standard input, then g's contents.
dcat Copy standard input to standard output.
```
-## Compile Application
+## Compile Standalone Application
### *nix
```sh
@@ -42,4 +50,5 @@ dart compile exe bin/dcat.dart
## Differences from [GNU cat](https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html#cat-invocation)
- No binary file support.
- - Line numbers are printed as `X:` where `X` is the line number.
+ - A line is considered terminated by either a `CR` (carriage return), a `LF` (line feed), a `CR+LF` sequence (DOS line ending).
+ - The non-printing `M-^?` notation is always used for unicode characters.
\ No newline at end of file
diff --git a/bin/dcat.dart b/bin/dcat.dart
index 7025cc6..33dcac0 100644
--- a/bin/dcat.dart
+++ b/bin/dcat.dart
@@ -8,33 +8,43 @@ import 'package:args/args.dart';
import 'package:dcat/dcat.dart';
import 'package:indent/indent.dart';
-const appName = libName;
+const appName = 'dcat';
const appVersion = '1.0.0';
const helpFlag = 'help';
const nonBlankFlag = 'number-nonblank';
const numberFlag = 'number';
+const showAllFlag = 'show-all';
const showEndsFlag = 'show-ends';
+const showNonPrintingEndsFlag = 'show-nonprinting-ends';
+const showNonPrintingFlag = 'show-nonprinting';
+const showNonPrintingTabsFlag = 'show-nonprinting-tabs';
const showTabsFlag = 'show-tabs';
const squeezeBlank = 'squeeze-blank';
const versionFlag = 'version';
/// Concatenates files specified in [arguments].
///
-/// Usage: `dcat [OPTION]... [FILE]...`
+/// Usage: `dcat [option] [file]…`
Future main(List arguments) async {
final parser = ArgParser();
Future returnCode;
exitCode = exitSuccess;
+ parser.addFlag(showAllFlag,
+ negatable: false, abbr: 'A', help: 'equivalent to -vET');
parser.addFlag(nonBlankFlag,
negatable: false,
abbr: 'b',
help: 'number nonempty output lines, overrides -n');
+ parser.addFlag(showNonPrintingEndsFlag,
+ negatable: false, abbr: 'e', help: 'equivalent to -vE');
parser.addFlag(showEndsFlag,
negatable: false, abbr: 'E', help: 'display \$ at end of each line');
parser.addFlag(helpFlag,
negatable: false, abbr: 'h', help: 'display this help and exit');
parser.addFlag(numberFlag,
negatable: false, abbr: 'n', help: 'number all output lines');
+ parser.addFlag(showNonPrintingTabsFlag,
+ negatable: false, abbr: 't', help: 'equivalent to -vT');
parser.addFlag(showTabsFlag,
negatable: false, abbr: 'T', help: 'display TAB characters as ^I');
parser.addFlag(squeezeBlank,
@@ -43,6 +53,11 @@ Future main(List arguments) async {
help: 'suppress repeated empty output lines');
parser.addFlag(versionFlag,
negatable: false, help: 'output version information and exit');
+ parser.addFlag('ignored', negatable: false, hide: true, abbr: 'u');
+ parser.addFlag(showNonPrintingFlag,
+ negatable: false,
+ abbr: 'v',
+ help: 'use ^ and M- notation, except for LFD and TAB');
final ArgResults argResults;
try {
@@ -59,12 +74,30 @@ Future main(List arguments) async {
returnCode = printVersion();
} else {
final paths = argResults.rest;
+ var showEnds = argResults[showEndsFlag];
+ var showTabs = argResults[showTabsFlag];
+ var showNonPrinting = argResults[showNonPrintingFlag];
+
+ if (argResults[showNonPrintingEndsFlag]) {
+ showNonPrinting = showEnds = true;
+ }
+
+ if (argResults[showNonPrintingTabsFlag]) {
+ showNonPrinting = showTabs = true;
+ }
+
+ if (argResults[showAllFlag]) {
+ showNonPrinting = showEnds = showTabs = true;
+ }
+
returnCode = cat(paths,
- showEnds: argResults[showEndsFlag],
+ appName: appName,
+ showEnds: showEnds,
showLineNumbers: argResults[numberFlag],
numberNonBlank: argResults[nonBlankFlag],
- showTabs: argResults[showTabsFlag],
- squeezeBlank: argResults[squeezeBlank]);
+ showTabs: showTabs,
+ squeezeBlank: argResults[squeezeBlank],
+ showNonPrinting: showNonPrinting);
}
exitCode = await returnCode;
@@ -76,7 +109,7 @@ Future printVersion() async {
print('''$appName (Dart cat) $appVersion
Copyright (C) 2021 Erik C. Thauvin
License: 3-Clause BSD
-
+
Inspired by
Written by Erik C. Thauvin ''');
return exitSuccess;
@@ -93,7 +126,7 @@ ${options.indent(2)}
Examples:
$appName f - g Output f's contents, then standard input, then g's contents.
$appName Copy standard input to standard output.
-
- Source and documentation: ''');
+
+Source and documentation: ''');
return exitSuccess;
}
diff --git a/doc/api/dcat/cat.html b/doc/api/dcat/cat.html
index a3cd7b9..47be894 100644
--- a/doc/api/dcat/cat.html
+++ b/doc/api/dcat/cat.html
@@ -54,12 +54,14 @@
Future <int >
cat (List <String > paths ,
-{List <String > ? log ,
+{String appName = '' ,
+List <String > ? log ,
bool showEnds = false ,
bool numberNonBlank = false ,
bool showLineNumbers = false ,
bool showTabs = false ,
-bool squeezeBlank = false }
+bool squeezeBlank = false ,
+bool showNonPrinting = false }
)
@@ -67,7 +69,7 @@
Concatenates files in paths
to stdout
The parameters are similar to the GNU cat utility .
-Specify a log
for debugging purpose.
+Specify a log
for debugging or testing purpose.
@@ -75,19 +77,21 @@ Specify a log
for debugging purpose.
Implementation
Future<int> cat(List<String> paths,
- {List<String>? log,
+ {String appName = '',
+ List<String>? log,
bool showEnds = false,
bool numberNonBlank = false,
bool showLineNumbers = false,
bool showTabs = false,
- bool squeezeBlank = false}) async {
+ bool squeezeBlank = false,
+ bool showNonPrinting = false}) async {
var lineNumber = 1;
var returnCode = 0;
log?.clear();
if (paths.isEmpty) {
final lines = await _readStdin();
await _writeLines(lines, lineNumber, log, showEnds, showLineNumbers,
- numberNonBlank, showTabs, squeezeBlank);
+ numberNonBlank, showTabs, squeezeBlank, showNonPrinting);
} else {
for (final path in paths) {
try {
@@ -99,8 +103,16 @@ Specify a log
for debugging purpose.
.bind(File(path).openRead())
.transform(const LineSplitter());
}
- lineNumber = await _writeLines(lines, lineNumber, log, showEnds,
- showLineNumbers, numberNonBlank, showTabs, squeezeBlank);
+ lineNumber = await _writeLines(
+ lines,
+ lineNumber,
+ log,
+ showEnds,
+ showLineNumbers,
+ numberNonBlank,
+ showTabs,
+ squeezeBlank,
+ showNonPrinting);
} on FileSystemException catch (e) {
final String? osMessage = e.osError?.message;
final String message;
@@ -109,11 +121,13 @@ Specify a log
for debugging purpose.
} else {
message = e.message;
}
- returnCode = await printError(message, path: path);
+ returnCode = await printError(message, appName: appName, path: path);
} on FormatException {
- returnCode = await printError('Binary file not supported.', path: path);
+ returnCode = await printError('Binary file not supported.',
+ appName: appName, path: path);
} catch (e) {
- returnCode = await printError(e.toString(), path: path);
+ returnCode =
+ await printError(e.toString(), appName: appName, path: path);
}
}
}
@@ -146,7 +160,6 @@ Specify a log
for debugging purpose.
Constants
exitFailure
exitSuccess
- libName
Functions
diff --git a/doc/api/dcat/dcat-library.html b/doc/api/dcat/dcat-library.html
index fd82879..68ffe31 100644
--- a/doc/api/dcat/dcat-library.html
+++ b/doc/api/dcat/dcat-library.html
@@ -49,6 +49,9 @@
+
+ Library to concatenate file(s) to standard output,
+
@@ -88,21 +91,6 @@
-
- libName
- → const String
-
-
-
-
-
-
-
-
- 'dcat'
-
-
-
@@ -112,7 +100,7 @@
- cat (List <String > paths , {List <String > ? log , bool showEnds = false , bool numberNonBlank = false , bool showLineNumbers = false , bool showTabs = false , bool squeezeBlank = false } )
+ cat (List <String > paths , {String appName = '' , List <String > ? log , bool showEnds = false , bool numberNonBlank = false , bool showLineNumbers = false , bool showTabs = false , bool squeezeBlank = false , bool showNonPrinting = false } )
→ Future <int >
@@ -125,7 +113,7 @@
- printError (String message , {String appName = libName , String path = '' } )
+ printError (String message , {String appName = '' , String path = '' } )
→ Future <int >
@@ -175,7 +163,6 @@
Constants
exitFailure
exitSuccess
- libName
Functions
diff --git a/doc/api/dcat/exitFailure-constant.html b/doc/api/dcat/exitFailure-constant.html
index e25ce4d..61eda37 100644
--- a/doc/api/dcat/exitFailure-constant.html
+++ b/doc/api/dcat/exitFailure-constant.html
@@ -89,7 +89,6 @@
Constants
exitFailure
exitSuccess
- libName
Functions
diff --git a/doc/api/dcat/exitSuccess-constant.html b/doc/api/dcat/exitSuccess-constant.html
index 059d175..9cb3baa 100644
--- a/doc/api/dcat/exitSuccess-constant.html
+++ b/doc/api/dcat/exitSuccess-constant.html
@@ -89,7 +89,6 @@
Constants
exitFailure
exitSuccess
- libName
Functions
diff --git a/doc/api/dcat/libName-constant.html b/doc/api/dcat/libName-constant.html
deleted file mode 100644
index a514a1a..0000000
--- a/doc/api/dcat/libName-constant.html
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
-
- libName constant - dcat library - Dart API
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- dcat
- dcat
- libName constant
-
- libName
-
-
-
-
-
-
-
-
-
-
- String
- const libName
-
-
-
-
-
-
-
- Implementation
- const libName = 'dcat';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/api/dcat/printError.html b/doc/api/dcat/printError.html
index 60b9029..36f3c3c 100644
--- a/doc/api/dcat/printError.html
+++ b/doc/api/dcat/printError.html
@@ -54,7 +54,7 @@
Future <int >
printError (String message ,
-{String appName = libName ,
+{String appName = '' ,
String path = '' }
)
@@ -69,12 +69,14 @@
Implementation
Future<int> printError(String message,
- {String appName = libName, String path = ''}) async {
- if (path.isNotEmpty) {
- stderr.writeln('$libName: $path: $message');
- } else {
- stderr.write('$libName: $message');
+ {String appName = '', String path = ''}) async {
+ if (appName.isNotEmpty) {
+ stderr.write('$appName: ');
}
+ if (path.isNotEmpty) {
+ stderr.write('$path: ');
+ }
+ stderr.writeln(message);
return exitFailure;
}
@@ -104,7 +106,6 @@
Constants
exitFailure
exitSuccess
- libName
Functions
diff --git a/doc/api/index.html b/doc/api/index.html
index a8c0f6e..08177ec 100644
--- a/doc/api/index.html
+++ b/doc/api/index.html
@@ -48,6 +48,8 @@
dcat: Concatenate File(s) to Standard Output
A cat command-line implemenation in Dart , inspired by the Write command-line apps sample code .
+Synopsis
+dcat copies each file, or standard input if none are given, to standard output.
Command-Line Usage
dcat --help
@@ -56,19 +58,23 @@ Concatenate FILE(s) to standard output.
With no FILE, or when FILE is -, read standard input.
- -b, --number-nonblank number nonempty output lines, overrides -n
- -E, --show-ends display $ at end of each line
- -h, --help display this help and exit
- -n, --number number all output lines
- -T, --show-tabs display TAB characters as ^I
- -s, --squeeze-blank suppress repeated empty output lines
- --version output version information and exit
+ -A, --show-all equivalent to -vET
+ -b, --number-nonblank number nonempty output lines, overrides -n
+ -e, --show-nonprinting-ends equivalent to -vE
+ -E, --show-ends display $ at end of each line
+ -h, --help display this help and exit
+ -n, --number number all output lines
+ -t, --show-nonprinting-tabs equivalent to -vT
+ -T, --show-tabs display TAB characters as ^I
+ -s, --squeeze-blank suppress repeated empty output lines
+ --version output version information and exit
+ -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
Examples:
dcat f - g Output f's contents, then standard input, then g's contents.
dcat Copy standard input to standard output.
-Compile Application
+Compile Standalone Application
*nix
dart compile exe -o bin/dcat bin/dcat.dart
@@ -78,7 +84,8 @@ Examples:
Differences from GNU cat
No binary file support.
-Line numbers are printed as X:
where X
is the line number.
+A line is considered terminated by either a CR
(carriage return), a LF
(line feed), a CR+LF
sequence (DOS line ending).
+The non-printing M-^?
notation is always used for unicode characters.
@@ -90,7 +97,7 @@ Examples:
dcat
-
+Library to concatenate file(s) to standard output,
diff --git a/doc/api/index.json b/doc/api/index.json
index 125e413..2af36b4 100644
--- a/doc/api/index.json
+++ b/doc/api/index.json
@@ -1 +1 @@
-[{"name":"dcat","qualifiedName":"dcat","href":"dcat/dcat-library.html","type":"library","overriddenDepth":0,"packageName":"dcat"},{"name":"cat","qualifiedName":"dcat.cat","href":"dcat/cat.html","type":"function","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"exitFailure","qualifiedName":"dcat.exitFailure","href":"dcat/exitFailure-constant.html","type":"top-level constant","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"exitSuccess","qualifiedName":"dcat.exitSuccess","href":"dcat/exitSuccess-constant.html","type":"top-level constant","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"libName","qualifiedName":"dcat.libName","href":"dcat/libName-constant.html","type":"top-level constant","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"printError","qualifiedName":"dcat.printError","href":"dcat/printError.html","type":"function","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}}]
+[{"name":"dcat","qualifiedName":"dcat","href":"dcat/dcat-library.html","type":"library","overriddenDepth":0,"packageName":"dcat"},{"name":"cat","qualifiedName":"dcat.cat","href":"dcat/cat.html","type":"function","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"exitFailure","qualifiedName":"dcat.exitFailure","href":"dcat/exitFailure-constant.html","type":"top-level constant","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"exitSuccess","qualifiedName":"dcat.exitSuccess","href":"dcat/exitSuccess-constant.html","type":"top-level constant","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}},{"name":"printError","qualifiedName":"dcat.printError","href":"dcat/printError.html","type":"function","overriddenDepth":0,"packageName":"dcat","enclosedBy":{"name":"dcat","type":"library"}}]
diff --git a/lib/dcat.dart b/lib/dcat.dart
index 0313ace..05ae1bb 100644
--- a/lib/dcat.dart
+++ b/lib/dcat.dart
@@ -2,33 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
+/// Library to concatenate file(s) to standard output,
library dcat;
import 'dart:convert';
import 'dart:io';
-const libName = 'dcat';
const exitFailure = 1;
const exitSuccess = 0;
/// Concatenates files in [paths] to [stdout]
///
/// The parameters are similar to the [GNU cat utility](https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html#cat-invocation).
-/// Specify a [log] for debugging purpose.
+/// Specify a [log] for debugging or testing purpose.
Future cat(List paths,
- {List? log,
+ {String appName = '',
+ List? log,
bool showEnds = false,
bool numberNonBlank = false,
bool showLineNumbers = false,
bool showTabs = false,
- bool squeezeBlank = false}) async {
+ bool squeezeBlank = false,
+ bool showNonPrinting = false}) async {
var lineNumber = 1;
var returnCode = 0;
log?.clear();
if (paths.isEmpty) {
final lines = await _readStdin();
await _writeLines(lines, lineNumber, log, showEnds, showLineNumbers,
- numberNonBlank, showTabs, squeezeBlank);
+ numberNonBlank, showTabs, squeezeBlank, showNonPrinting);
} else {
for (final path in paths) {
try {
@@ -40,8 +42,16 @@ Future cat(List paths,
.bind(File(path).openRead())
.transform(const LineSplitter());
}
- lineNumber = await _writeLines(lines, lineNumber, log, showEnds,
- showLineNumbers, numberNonBlank, showTabs, squeezeBlank);
+ lineNumber = await _writeLines(
+ lines,
+ lineNumber,
+ log,
+ showEnds,
+ showLineNumbers,
+ numberNonBlank,
+ showTabs,
+ squeezeBlank,
+ showNonPrinting);
} on FileSystemException catch (e) {
final String? osMessage = e.osError?.message;
final String message;
@@ -50,25 +60,63 @@ Future cat(List paths,
} else {
message = e.message;
}
- returnCode = await printError(message, path: path);
+ returnCode = await printError(message, appName: appName, path: path);
} on FormatException {
- returnCode = await printError('Binary file not supported.', path: path);
+ returnCode = await printError('Binary file not supported.',
+ appName: appName, path: path);
} catch (e) {
- returnCode = await printError(e.toString(), path: path);
+ returnCode =
+ await printError(e.toString(), appName: appName, path: path);
}
}
}
return returnCode;
}
+/// Parses line with non-printing characters.
+Future _parseNonPrinting(String line, bool showTabs) async {
+ final sb = StringBuffer();
+ for (var ch in line.runes) {
+ if (ch >= 32) {
+ if (ch < 127) {
+ sb.writeCharCode(ch);
+ } else if (ch == 127) {
+ sb.write('^?');
+ } else {
+ sb.write('M-');
+ if (ch >= 128 + 32) {
+ if (ch < 128 + 127) {
+ sb.writeCharCode(ch - 128);
+ } else {
+ sb.write('^?');
+ }
+ } else {
+ sb
+ ..write('^')
+ ..writeCharCode(ch - 128 + 64);
+ }
+ }
+ } else if (ch == 9 && !showTabs) {
+ sb.write('\t');
+ } else {
+ sb
+ ..write('^')
+ ..writeCharCode(ch + 64);
+ }
+ }
+ return sb.toString();
+}
+
/// Prints the [appName], [path] and error [message] to [stderr].
Future printError(String message,
- {String appName = libName, String path = ''}) async {
- if (path.isNotEmpty) {
- stderr.writeln('$libName: $path: $message');
- } else {
- stderr.write('$libName: $message');
+ {String appName = '', String path = ''}) async {
+ if (appName.isNotEmpty) {
+ stderr.write('$appName: ');
}
+ if (path.isNotEmpty) {
+ stderr.write('$path: ');
+ }
+ stderr.writeln(message);
return exitFailure;
}
@@ -83,7 +131,8 @@ Future _writeLines(Stream lines, int lineNumber,
bool showLineNumbers = false,
bool showNonBlank = false,
bool showTabs = false,
- bool squeezeBlank = false]) async {
+ bool squeezeBlank = false,
+ bool showNonPrinting = false]) async {
var emptyLine = 0;
final sb = StringBuffer();
await for (final line in lines) {
@@ -95,14 +144,18 @@ Future _writeLines(Stream lines, int lineNumber,
} else {
emptyLine = 0;
}
- if (showNonBlank || showLineNumbers) {
- sb.write('${lineNumber++}: ');
+ if (showLineNumbers || (showNonBlank && line.isNotEmpty)) {
+ sb.write('${lineNumber++} '.padLeft(8));
}
- if (showTabs) {
+
+ if (showNonPrinting) {
+ sb.write(await _parseNonPrinting(line, showTabs));
+ } else if (showTabs) {
sb.write(line.replaceAll('\t', '^I'));
} else {
sb.write(line);
}
+
if (showEnds) {
sb.write('\$');
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 16b6383..80aa13d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -9,6 +9,6 @@ environment:
dev_dependencies:
lints: ^1.0.0
test: ^1.18.2
-dependencies:
+dependencies:
args: ^2.3.0
indent: ^2.0.0
diff --git a/test/dcat_test.dart b/test/dcat_test.dart
index 74fb8d6..1feef14 100644
--- a/test/dcat_test.dart
+++ b/test/dcat_test.dart
@@ -7,96 +7,139 @@ void main() {
final List log = [];
int exitCode;
- test('Test Help', () async {
- expect(app.main(['-h']), completion(equals(0)));
- expect(app.main(['--help']), completion(equals(0)));
- exitCode = await app.main(['-h']);
- expect(exitCode, equals(exitSuccess));
+ group('app', () {
+ test('Test Help', () async {
+ expect(app.main(['-h']), completion(equals(0)));
+ expect(app.main(['--help']), completion(equals(0)));
+ exitCode = await app.main(['-h']);
+ expect(exitCode, equals(exitSuccess));
+ });
+
+ test('Test --version', () async {
+ expect(app.main(['--version']), completion(equals(0)));
+ exitCode = await app.main(['--version']);
+ expect(exitCode, equals(exitSuccess));
+ });
+
+ test('Test directory', () async {
+ exitCode = await app.main(['bin']);
+ expect(exitCode, equals(exitFailure));
+ });
+
+ test('Test missing file', () async {
+ exitCode = await app.main(['foo']);
+ expect(exitCode, equals(exitFailure), reason: 'foo not found');
+ exitCode = await app.main(['bin/dcat.dart', 'foo']);
+ expect(exitCode, equals(exitFailure), reason: 'one missing file');
+ });
});
- test('Test --version', () async {
- expect(app.main(['--version']), completion(equals(0)));
- exitCode = await app.main(['--version']);
- expect(exitCode, equals(exitSuccess));
- });
+ group('lib', () {
+ test('Test cat source', () async {
+ await cat(['bin/dcat.dart'], log: log);
+ expect(log.isEmpty, false, reason: 'log is empty');
+ expect(log.first, startsWith('// Copyright (c)'),
+ reason: 'has copyright');
+ expect(log.last, equals('}'));
+ });
- test('Test directory', () async {
- exitCode = await app.main(['bin']);
- expect(exitCode, equals(exitFailure));
- });
-
- test('Test missing file', () async {
- exitCode = await app.main(['foo']);
- expect(exitCode, equals(exitFailure), reason: 'foo not found');
- exitCode = await app.main(['bin/dcat.dart', 'foo']);
- expect(exitCode, equals(exitFailure), reason: 'one missing file');
- });
-
- test('Test cat source', () async {
- await cat(['bin/dcat.dart'], log: log);
- expect(log.isEmpty, false, reason: 'log is empty');
- expect(log.first, startsWith('// Copyright (c)'), reason: 'has copyright');
- expect(log.last, equals('}'));
- });
-
- test('Test cat -n source', () async {
- exitCode = await cat(['bin/dcat.dart'], log: log, showLineNumbers: true);
- expect(exitCode, 0, reason: 'result code is 0');
- expect(log.first, startsWith('1: // Copyright (c)'),
- reason: 'has copyright');
- expect(log.last, endsWith(': }'), reason: 'last line');
- for (final String line in log) {
- expect(line, matches('^\\d+: .*'), reason: 'has line number');
- }
- });
-
- test('Test cat -E', () async {
- await cat(['test/test.txt'], log: log, showEnds: true);
- var hasBlank = false;
- for (final String line in log) {
- expect(line, endsWith('\$'));
- if (line == '\$') {
- hasBlank = true;
+ test('Test cat -n source', () async {
+ exitCode = await cat(['bin/dcat.dart'], log: log, showLineNumbers: true);
+ expect(exitCode, 0, reason: 'result code is 0');
+ expect(log.first, startsWith(' 1 // Copyright (c)'),
+ reason: 'has copyright');
+ expect(log.last, endsWith(' }'), reason: 'last line');
+ for (final String line in log) {
+ expect(line, matches('^ +\\d+ .*'), reason: 'has line number');
}
- }
- expect(hasBlank, true, reason: 'has blank line');
- });
+ });
- test('Test cat -bE', () async {
- await cat(['test/test.txt'],
- log: log, numberNonBlank: true, showEnds: true);
- var hasBlank = false;
- for (final String line in log) {
- expect(line, endsWith('\$'));
- if (line.contains(RegExp(r'^\d+: .*\$$'))) {
- hasBlank = true;
- }
- }
- expect(hasBlank, true, reason: 'has blank line');
- });
+ test('Test cat source test', () async {
+ await cat(['bin/dcat.dart', 'test/test.txt'], log: log);
+ expect(log.length, greaterThan(10), reason: 'more than 10 lines');
+ expect(log.first, startsWith('// Copyright'),
+ reason: 'start with copyright');
+ expect(log.last, endsWith('✓'), reason: 'end with checkmark');
+ });
- test('Test cat -T', () async {
- await cat(['test/test.txt'], log: log, showTabs: true);
- var hasTab = false;
- for (final String line in log) {
- if (line.startsWith('^I')) {
- hasTab = true;
- break;
+ test('Test cat -E', () async {
+ await cat(['test/test.txt'], log: log, showEnds: true);
+ var hasBlank = false;
+ for (final String line in log) {
+ expect(line, endsWith('\$'));
+ if (line == '\$') {
+ hasBlank = true;
+ }
}
- }
- expect(hasTab, true, reason: 'has tab');
- });
+ expect(hasBlank, true, reason: 'has blank line');
+ expect(log.last, endsWith('✓\$'), reason: 'has unicode');
+ });
- test('Test cat -s', () async {
- await cat(['test/test.txt'], log: log, squeezeBlank: true);
- var hasSqueeze = true;
- var prevLine = 'foo';
- for (final String line in log) {
- if (line == prevLine) {
- hasSqueeze = false;
+ test('Test cat -bE', () async {
+ await cat(['test/test.txt'],
+ log: log, numberNonBlank: true, showEnds: true);
+ var hasBlank = false;
+ for (final String line in log) {
+ expect(line, endsWith('\$'));
+ if (line.contains(RegExp(r'^ +\d+ .*\$$'))) {
+ hasBlank = true;
+ }
}
- prevLine = line;
- }
- expect(hasSqueeze, true, reason: 'has squeeze');
+ expect(hasBlank, true, reason: 'has blank line');
+ });
+
+ test('Test cat -T', () async {
+ await cat(['test/test.txt'], log: log, showTabs: true);
+ var hasTab = false;
+ for (final String line in log) {
+ if (line.startsWith('^I')) {
+ hasTab = true;
+ break;
+ }
+ }
+ expect(hasTab, true, reason: 'has tab');
+ });
+
+ test('Test cat -s', () async {
+ await cat(['test/test.txt'], log: log, squeezeBlank: true);
+ var hasSqueeze = true;
+ var prevLine = 'foo';
+ for (final String line in log) {
+ if (line == prevLine) {
+ hasSqueeze = false;
+ }
+ prevLine = line;
+ }
+ expect(hasSqueeze, true, reason: 'has squeeze');
+ });
+
+ test('Test cat -A', () async {
+ await cat(['test/test.txt'],
+ log: log, showNonPrinting: true, showEnds: true, showTabs: true);
+ expect(log.last, equals('^I^A^B^C^DM-^?\$'));
+ });
+
+ test('Test cat -t', () async {
+ await cat(['test/test.txt'],
+ log: log, showNonPrinting: true, showTabs: true);
+ expect(log.last, equals('^I^A^B^C^DM-^?'));
+ });
+
+ test('Test cat-Abs', () async {
+ await cat(['test/test.txt'],
+ log: log,
+ showNonPrinting: true,
+ showEnds: true,
+ showTabs: true,
+ numberNonBlank: true,
+ squeezeBlank: true);
+ var blankLines = 0;
+ for (final String line in log) {
+ if (line == '\$') {
+ blankLines++;
+ }
+ }
+ expect(blankLines, 2, reason: 'only 2 blank lines.');
+ });
});
}
diff --git a/test/test.txt b/test/test.txt
index a0d8abe..5abf6c3 100644
--- a/test/test.txt
+++ b/test/test.txt
@@ -4,4 +4,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ ✓