Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dev_dependencies:
build_runner: ^2.0.0
build_verify: ^3.0.0
build_version: ^2.1.1
checks: ^0.3.1
dart_flutter_team_lints: ^3.0.0
http: ^1.1.0
path: ^1.8.0
Expand Down
53 changes: 25 additions & 28 deletions test/command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import 'dart:async';
import 'dart:io';

import 'package:checks/checks.dart';
import 'package:dhttpd/src/version.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
import 'package:test/scaffolding.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:test_process/test_process.dart';

Expand All @@ -22,7 +23,7 @@ Future<void> _versionCheck() async {
final process = await _runApp(['--version']);
final output = (await process.stdoutStream().join('\n')).trim();
await process.shouldExit(0);
expect(output, packageVersion);
check(output).equals(packageVersion);
}

Future<void> _readmeCheck(List<String> args) async {
Expand All @@ -42,7 +43,7 @@ $output

printOnFailure(expected);

expect(expected, r'''```console
check(expected).equals(r'''```console
$ dhttpd --help
--headers=<headers> HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value
--host=<host> The hostname to listen on.
Expand All @@ -59,7 +60,7 @@ $ dhttpd --help
--version Prints the version of dhttpd.
```''');

expect(readme.readAsStringSync(), contains(expected));
check(readme.readAsStringSync()).contains(expected);
}

Future<void> _headersCheck() async {
Expand All @@ -79,32 +80,28 @@ Future<void> _headersCheck() async {
' X-Spaced-Key = spaced-value ',
]);
final line = await process.stdout.next;
expect(line, 'Serving ${d.sandbox} at http://localhost:8001');
check(line).equals('Serving ${d.sandbox} at http://localhost:8001');

final response = await http.get(Uri.parse('http://localhost:8001'));
expect(response.statusCode, 200);
expect(response.headers['x-custom'], 'Value1');
expect(response.headers['x-another'], 'Value 2');
expect(response.headers['x-third'], 'Value3');
expect(response.headers['x-empty-val'], '');
expect(response.headers['x-with-equals'], 'foo=bar');
expect(response.headers['x-spaced-key'], 'spaced-value');
check(response.statusCode).equals(200);
check(response.headers['x-custom']).equals('Value1');
check(response.headers['x-another']).equals('Value 2');
check(response.headers['x-third']).equals('Value3');
check(response.headers['x-empty-val']).equals('');
check(response.headers['x-with-equals']).equals('foo=bar');
check(response.headers['x-spaced-key']).equals('spaced-value');

await process.kill();
}

Future<void> _invalidHeadersCheck() async {
final process = await _runApp(['--headers', 'invalid-format']);
expect(
check(
await process.stderr.next,
contains('Invalid header segment: "invalid-format". Expected "key=value".'),
);
expect(
await process.stderr.next,
contains(
'For values with semicolons, use a separate --headers flag '
'per header.',
),
).contains('Invalid header segment: "invalid-format". Expected "key=value".');
check(await process.stderr.next).contains(
'For values with semicolons, use a separate --headers flag '
'per header.',
);
await process.shouldExit(64);
}
Expand All @@ -114,11 +111,11 @@ Future<void> _outputCheck() async {

final process = await _runApp(['--port=8000', '--path', d.sandbox]);
final line = await process.stdout.next;
expect(line, 'Serving ${d.sandbox} at http://localhost:8000');
check(line).equals('Serving ${d.sandbox} at http://localhost:8000');

final response = await http.get(Uri.parse('http://localhost:8000'));
expect(response.statusCode, 200);
expect(response.body, 'Hello World');
check(response.statusCode).equals(200);
check(response.body).equals('Hello World');

await process.kill();
}
Expand All @@ -133,14 +130,14 @@ Future<void> _quietCheck() async {
'--quiet',
]);
final line = await process.stdout.next;
expect(line, 'Serving ${d.sandbox} at http://localhost:8002');
check(line).equals('Serving ${d.sandbox} at http://localhost:8002');

final response = await http.get(Uri.parse('http://localhost:8002'));
expect(response.statusCode, 200);
expect(response.body, 'Hello World');
check(response.statusCode).equals(200);
check(response.body).equals('Hello World');

await process.kill();
expect(await process.stdout.rest.toList(), isEmpty);
check(await process.stdout.rest.toList()).isEmpty();
}

Future<TestProcess> _runApp(List<String> args, {String? workingDirectory}) =>
Expand Down
30 changes: 15 additions & 15 deletions test/dhttpd_test.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import 'dart:io';

import 'package:checks/checks.dart';
import 'package:dhttpd/dhttpd.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart' as http_io;
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test/scaffolding.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;

void main() {
Expand All @@ -21,12 +22,11 @@ void main() {

final response = await http.get(Uri.parse(server.urlBase));

expect(response.statusCode, HttpStatus.ok);
expect(response.body, 'Hello World');
expect(
check(response.statusCode).equals(HttpStatus.ok);
check(response.body).equals('Hello World');
check(
response.headers[HttpHeaders.contentTypeHeader],
contains('text/html'),
);
).isNotNull().contains('text/html');
});

test('custom headers', () async {
Expand All @@ -40,8 +40,8 @@ void main() {

final response = await http.get(Uri.parse(server.urlBase));

expect(response.statusCode, HttpStatus.ok);
expect(response.headers['x-test-header'], 'TestValue');
check(response.statusCode).equals(HttpStatus.ok);
check(response.headers['x-test-header']).equals('TestValue');
});

test('list files', () async {
Expand All @@ -55,8 +55,8 @@ void main() {

final response = await http.get(Uri.parse(server.urlBase));

expect(response.statusCode, HttpStatus.ok);
expect(response.body, contains('file.txt'));
check(response.statusCode).equals(HttpStatus.ok);
check(response.body).contains('file.txt');
});

test('404 handling', () async {
Expand All @@ -66,7 +66,7 @@ void main() {
Uri.parse('${server.urlBase}/notfound.html'),
);

expect(response.statusCode, HttpStatus.notFound);
check(response.statusCode).equals(HttpStatus.notFound);
});

test('SSL configuration', () async {
Expand All @@ -87,17 +87,17 @@ void main() {
sslPassword: 'dartdart',
);

expect(server.isSSL, isTrue);
expect(server.urlBase, startsWith('https://'));
check(server.isSSL).isTrue();
check(server.urlBase).startsWith('https://');

// Create a client that ignores SSL errors for self-signed certificates
final ioClient = HttpClient()..badCertificateCallback = ((_, _, _) => true);
final client = http_io.IOClient(ioClient);

try {
final response = await client.get(Uri.parse(server.urlBase));
expect(response.statusCode, HttpStatus.ok);
expect(response.body, 'Hello SSL');
check(response.statusCode).equals(HttpStatus.ok);
check(response.body).equals('Hello SSL');
} finally {
client.close();
}
Expand Down
2 changes: 1 addition & 1 deletion test/ensure_build_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
library;

import 'package:build_verify/build_verify.dart';
import 'package:test/test.dart';
import 'package:test/scaffolding.dart';

void main() {
test('ensure_build', expectBuildClean);
Expand Down
65 changes: 24 additions & 41 deletions test/utils_test.dart
Original file line number Diff line number Diff line change
@@ -1,79 +1,62 @@
import 'package:checks/checks.dart';
import 'package:dhttpd/src/utils.dart';
import 'package:test/test.dart';
import 'package:test/scaffolding.dart';

void main() {
group('parseKeyValuePairs', () {
test('parses a single key-value pair', () {
expect(parseKeyValuePairs(['Key=Value']), equals({'Key': 'Value'}));
check(parseKeyValuePairs(['Key=Value'])).deepEquals({'Key': 'Value'});
});

test('parses multiple pairs separated by semicolons', () {
expect(
check(
parseKeyValuePairs(['Key1=Value1;Key2=Value2']),
equals({'Key1': 'Value1', 'Key2': 'Value2'}),
);
).deepEquals({'Key1': 'Value1', 'Key2': 'Value2'});
});

test('parses multiple header strings', () {
expect(
check(
parseKeyValuePairs(['Key1=Value1', 'Key2=Value2']),
equals({'Key1': 'Value1', 'Key2': 'Value2'}),
);
).deepEquals({'Key1': 'Value1', 'Key2': 'Value2'});
});

test('trims whitespace around keys and values', () {
expect(
check(
parseKeyValuePairs([' Key1 = Value1 ; Key2=Value2 ']),
equals({'Key1': 'Value1', 'Key2': 'Value2'}),
);
).deepEquals({'Key1': 'Value1', 'Key2': 'Value2'});
});

test('ignores empty segments', () {
expect(
check(
parseKeyValuePairs(['Key=Value;;;Key2=Value2']),
equals({'Key': 'Value', 'Key2': 'Value2'}),
);
).deepEquals({'Key': 'Value', 'Key2': 'Value2'});
});

test('allows empty values', () {
expect(parseKeyValuePairs(['Key=']), equals({'Key': ''}));
expect(
check(parseKeyValuePairs(['Key='])).deepEquals({'Key': ''});
check(
parseKeyValuePairs(['Key= ; Key2=Value']),
equals({'Key': '', 'Key2': 'Value'}),
);
).deepEquals({'Key': '', 'Key2': 'Value'});
});

test('handles values with equals signs', () {
expect(
check(
parseKeyValuePairs(['Key=Value=With=Equals']),
equals({'Key': 'Value=With=Equals'}),
);
).deepEquals({'Key': 'Value=With=Equals'});
});

test('throws FormatException if a segment lacks an equals sign', () {
expect(
() => parseKeyValuePairs(['KeyOnly']),
throwsA(
isA<FormatException>().having(
(e) => e.message,
'message',
contains('Expected "key=value"'),
),
),
);
check(() => parseKeyValuePairs(['KeyOnly']))
.throws<FormatException>()
.has((e) => e.message, 'message')
.contains('Expected "key=value"');
});

test('throws FormatException if key is empty', () {
expect(
() => parseKeyValuePairs(['=Value']),
throwsA(
isA<FormatException>().having(
(e) => e.message,
'message',
contains('Key cannot be empty'),
),
),
);
check(() => parseKeyValuePairs(['=Value']))
.throws<FormatException>()
.has((e) => e.message, 'message')
.contains('Key cannot be empty');
});
});
}