add(angel3): adding re-branded angel3 mock_request package
This commit is contained in:
parent
9148934aa6
commit
d884105ded
16 changed files with 1127 additions and 0 deletions
71
packages/mock_request/.gitignore
vendored
Normal file
71
packages/mock_request/.gitignore
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
# See https://www.dartlang.org/tools/private-files.html
|
||||||
|
|
||||||
|
# Files and directories created by pub
|
||||||
|
.dart_tool
|
||||||
|
.packages
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# If you're building an application, you may want to check-in your pubspec.lock
|
||||||
|
pubspec.lock
|
||||||
|
|
||||||
|
# Directory created by dartdoc
|
||||||
|
# If you don't generate documentation locally you can remove this line.
|
||||||
|
doc/api/
|
||||||
|
|
||||||
|
### Dart template
|
||||||
|
# See https://www.dartlang.org/tools/private-files.html
|
||||||
|
|
||||||
|
# Files and directories created by pub
|
||||||
|
|
||||||
|
# SDK 1.20 and later (no longer creates packages directories)
|
||||||
|
|
||||||
|
# Older SDK versions
|
||||||
|
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
|
||||||
|
.project
|
||||||
|
.buildlog
|
||||||
|
**/packages/
|
||||||
|
|
||||||
|
|
||||||
|
# Files created by dart2js
|
||||||
|
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||||
|
# rules if you intend to use dart2js directly
|
||||||
|
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||||
|
# differentiate from explicit Javascript files)
|
||||||
|
*.dart.js
|
||||||
|
*.part.js
|
||||||
|
*.js.deps
|
||||||
|
*.js.map
|
||||||
|
*.info.json
|
||||||
|
|
||||||
|
# Directory created by dartdoc
|
||||||
|
|
||||||
|
# Don't commit pubspec lock file
|
||||||
|
# (Library packages only! Remove pattern if developing an application package)
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff:
|
||||||
|
|
||||||
|
## VsCode
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
.idea/
|
||||||
|
/out/
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
12
packages/mock_request/AUTHORS.md
Normal file
12
packages/mock_request/AUTHORS.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
||||||
|
code base to support NNBD.
|
||||||
|
|
||||||
|
* __[Tobe O](thosakwe@gmail.com)__
|
||||||
|
|
||||||
|
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
||||||
|
is no longer involved with the project.
|
78
packages/mock_request/CHANGELOG.md
Normal file
78
packages/mock_request/CHANGELOG.md
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
# Change Log
|
||||||
|
|
||||||
|
## 8.1.1
|
||||||
|
|
||||||
|
* Updated repository link
|
||||||
|
|
||||||
|
## 8.1.0
|
||||||
|
|
||||||
|
* Updated `lints` to 3.0.0
|
||||||
|
|
||||||
|
## 8.0.0
|
||||||
|
|
||||||
|
* Require Dart >= 3.0
|
||||||
|
* Updated `http` to 1.0.0
|
||||||
|
|
||||||
|
## 7.0.1
|
||||||
|
|
||||||
|
* Fixed `BytesBuilder` warnings
|
||||||
|
|
||||||
|
## 7.0.0
|
||||||
|
|
||||||
|
* Require Dart >= 2.17
|
||||||
|
|
||||||
|
## 6.0.0
|
||||||
|
|
||||||
|
* Require Dart >= 2.16
|
||||||
|
|
||||||
|
## 5.0.0
|
||||||
|
|
||||||
|
* Skipped release
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
|
* Skipped release
|
||||||
|
|
||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
* Skipped release
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
* Updated linter to `package:lints`
|
||||||
|
|
||||||
|
## 2.0.2
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
* Updated test cases
|
||||||
|
|
||||||
|
## 2.0.1
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
* Migrated to work with Dart >= 2.12 NNBD
|
||||||
|
|
||||||
|
## 1.0.7
|
||||||
|
|
||||||
|
* Prepare for upcoming Dart SDK change where `HttpHeaders` methods
|
||||||
|
`add` and `set` take an additional optional parameter `preserveHeaderCase` (thanks @domesticmouse!).
|
||||||
|
|
||||||
|
## 1.0.6
|
||||||
|
|
||||||
|
* Prepare for upcoming Dart SDK change whereby `HttpRequest` implements
|
||||||
|
`Stream<Uint8List>` rather than `Stream<List<int>>`.
|
||||||
|
|
||||||
|
## 1.0.5
|
||||||
|
|
||||||
|
* Add `toString` to `MockHttpHeaders`.
|
||||||
|
|
||||||
|
## 1.0.4
|
||||||
|
|
||||||
|
* Fix for `ifModifiedSince`
|
||||||
|
|
||||||
|
## 1.0.3
|
||||||
|
|
||||||
|
* Dart2 fixes
|
||||||
|
* Apparently fix hangs that break Angel tests
|
29
packages/mock_request/LICENSE
Normal file
29
packages/mock_request/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
packages/mock_request/README.md
Normal file
26
packages/mock_request/README.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Mock HTTP Request
|
||||||
|
|
||||||
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_mock_request?include_prereleases)
|
||||||
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/mock_request/LICENSE)
|
||||||
|
|
||||||
|
**Forked from `mock_request` to support NNBD**
|
||||||
|
|
||||||
|
Manufacture dart:io HttpRequests, HttpResponses, HttpHeaders, etc. This makes it possible to test server-side Dart applications without having to ever bind to a port.
|
||||||
|
|
||||||
|
This package was originally designed to make testing [Angel3](https://angel3-framework.web.app/) applications smoother, but works with any Dart-based server.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```dart
|
||||||
|
var rq = MockHttpRequest('GET', Uri.parse('/foo'));
|
||||||
|
await rq.close();
|
||||||
|
await app.handleRequest(rq); // Run within your server-side application
|
||||||
|
var rs = rq.response;
|
||||||
|
expect(rs.statusCode, equals(200));
|
||||||
|
expect(await rs.transform(UTF8.decoder).join(),
|
||||||
|
equals(JSON.encode('Hello, world!')));
|
||||||
|
```
|
||||||
|
|
||||||
|
More examples can be found in the included test cases.
|
1
packages/mock_request/analysis_options.yaml
Normal file
1
packages/mock_request/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
8
packages/mock_request/example/main.dart
Normal file
8
packages/mock_request/example/main.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:platform_mock_request/platform_mock_request.dart';
|
||||||
|
|
||||||
|
Future<void> main() async {
|
||||||
|
var rq =
|
||||||
|
MockHttpRequest('GET', Uri.parse('/foo'), persistentConnection: false);
|
||||||
|
await rq.close();
|
||||||
|
}
|
6
packages/mock_request/lib/platform_mock_request.dart
Normal file
6
packages/mock_request/lib/platform_mock_request.dart
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export 'src/connection_info.dart';
|
||||||
|
export 'src/headers.dart';
|
||||||
|
export 'src/lockable_headers.dart';
|
||||||
|
export 'src/request.dart';
|
||||||
|
export 'src/response.dart';
|
||||||
|
export 'src/session.dart';
|
13
packages/mock_request/lib/src/connection_info.dart
Normal file
13
packages/mock_request/lib/src/connection_info.dart
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
class MockHttpConnectionInfo implements HttpConnectionInfo {
|
||||||
|
@override
|
||||||
|
final InternetAddress remoteAddress;
|
||||||
|
@override
|
||||||
|
final int localPort, remotePort;
|
||||||
|
|
||||||
|
MockHttpConnectionInfo(
|
||||||
|
{required this.remoteAddress,
|
||||||
|
this.localPort = 8080,
|
||||||
|
this.remotePort = 80});
|
||||||
|
}
|
174
packages/mock_request/lib/src/headers.dart
Normal file
174
packages/mock_request/lib/src/headers.dart
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
class MockHttpHeaders implements HttpHeaders {
|
||||||
|
final Map<String, List<String>> _data = {};
|
||||||
|
final List<String> _noFolding = [];
|
||||||
|
//Uri? _host;
|
||||||
|
String? _hostname;
|
||||||
|
int _port = 80;
|
||||||
|
|
||||||
|
List<String> get doNotFold => List<String>.unmodifiable(_noFolding);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ContentType get contentType {
|
||||||
|
if (_data.containsKey(HttpHeaders.contentTypeHeader)) {
|
||||||
|
return ContentType.parse(_data[HttpHeaders.contentTypeHeader]!.join(','));
|
||||||
|
} else {
|
||||||
|
return ContentType.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
set contentType(ContentType? value) =>
|
||||||
|
set(HttpHeaders.contentTypeHeader, value?.value ?? ContentType.html);
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime get date => _data.containsKey(HttpHeaders.dateHeader)
|
||||||
|
? HttpDate.parse(_data[HttpHeaders.dateHeader]!.join(','))
|
||||||
|
: DateTime.now();
|
||||||
|
|
||||||
|
@override
|
||||||
|
set date(DateTime? value) =>
|
||||||
|
set(HttpHeaders.dateHeader, HttpDate.format(value ?? DateTime.now()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime get expires => _data.containsKey(HttpHeaders.expiresHeader)
|
||||||
|
? HttpDate.parse(_data[HttpHeaders.expiresHeader]!.join(','))
|
||||||
|
: DateTime.now();
|
||||||
|
|
||||||
|
@override
|
||||||
|
set expires(DateTime? value) =>
|
||||||
|
set(HttpHeaders.expiresHeader, HttpDate.format(value ?? DateTime.now()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime get ifModifiedSince =>
|
||||||
|
_data.containsKey(HttpHeaders.ifModifiedSinceHeader)
|
||||||
|
? HttpDate.parse(_data[HttpHeaders.ifModifiedSinceHeader]!.join(','))
|
||||||
|
: DateTime.now();
|
||||||
|
|
||||||
|
@override
|
||||||
|
set ifModifiedSince(DateTime? value) => set(HttpHeaders.ifModifiedSinceHeader,
|
||||||
|
HttpDate.format(value ?? DateTime.now()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get host {
|
||||||
|
return _hostname;
|
||||||
|
/*
|
||||||
|
if (_host != null) {
|
||||||
|
return _host!.host;
|
||||||
|
} else if (_data.containsKey(HttpHeaders.hostHeader)) {
|
||||||
|
_host = Uri.parse(_data[HttpHeaders.hostHeader]!.join(','));
|
||||||
|
return _host!.host;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get port {
|
||||||
|
return _port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String>? operator [](String name) => _data[name.toLowerCase()];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||||
|
var lower = preserveHeaderCase ? name : name.toLowerCase();
|
||||||
|
|
||||||
|
if (_data.containsKey(lower)) {
|
||||||
|
if (value is Iterable) {
|
||||||
|
_data[lower]!.addAll(value.map((x) => x.toString()).toList());
|
||||||
|
} else {
|
||||||
|
_data[lower]!.add(value.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value is Iterable) {
|
||||||
|
_data[lower] = value.map((x) => x.toString()).toList();
|
||||||
|
} else {
|
||||||
|
_data[lower] = [value.toString()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clear() {
|
||||||
|
_data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void forEach(void Function(String name, List<String> values) action) {
|
||||||
|
_data.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void noFolding(String name) {
|
||||||
|
_noFolding.add(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void remove(String name, Object value) {
|
||||||
|
var lower = name.toLowerCase();
|
||||||
|
|
||||||
|
if (_data.containsKey(lower)) {
|
||||||
|
if (value is Iterable) {
|
||||||
|
for (var x in value) {
|
||||||
|
_data[lower]!.remove(x.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_data[lower]!.remove(value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeAll(String name) {
|
||||||
|
_data.remove(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void set(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||||
|
var lower = preserveHeaderCase ? name : name.toLowerCase();
|
||||||
|
_data.remove(lower);
|
||||||
|
|
||||||
|
if (value is Iterable) {
|
||||||
|
_data[lower] = value.map((x) => x.toString()).toList();
|
||||||
|
} else {
|
||||||
|
_data[lower] = [value.toString()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? value(String name) => _data[name.toLowerCase()]?.join(',');
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var b = StringBuffer();
|
||||||
|
_data.forEach((k, v) {
|
||||||
|
b.write('$k: ');
|
||||||
|
b.write(v.join(','));
|
||||||
|
b.writeln();
|
||||||
|
});
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool chunkedTransferEncoding = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int contentLength = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool persistentConnection = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set host(String? host) {
|
||||||
|
_hostname = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
set port(int? port) {
|
||||||
|
_port = port ?? 80;
|
||||||
|
}
|
||||||
|
}
|
67
packages/mock_request/lib/src/lockable_headers.dart
Normal file
67
packages/mock_request/lib/src/lockable_headers.dart
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import 'headers.dart';
|
||||||
|
|
||||||
|
/// Headers that can be locked to editing, i.e. after a request body has been written.
|
||||||
|
class LockableMockHttpHeaders extends MockHttpHeaders {
|
||||||
|
bool _locked = false;
|
||||||
|
|
||||||
|
StateError _stateError() =>
|
||||||
|
StateError('Cannot modify headers after they have been write-locked.');
|
||||||
|
|
||||||
|
void lock() {
|
||||||
|
_locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.add(name, value, preserveHeaderCase: preserveHeaderCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clear() {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void noFolding(String name) {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.noFolding(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void remove(String name, Object value) {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.remove(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeAll(String name) {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.removeAll(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void set(String name, Object value, {bool preserveHeaderCase = false}) {
|
||||||
|
if (_locked) {
|
||||||
|
throw _stateError();
|
||||||
|
} else {
|
||||||
|
super.set(name, value, preserveHeaderCase: preserveHeaderCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
323
packages/mock_request/lib/src/request.dart
Normal file
323
packages/mock_request/lib/src/request.dart
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:charcode/ascii.dart';
|
||||||
|
import 'connection_info.dart';
|
||||||
|
import 'lockable_headers.dart';
|
||||||
|
import 'response.dart';
|
||||||
|
import 'session.dart';
|
||||||
|
|
||||||
|
class MockHttpRequest
|
||||||
|
implements HttpRequest, StreamSink<List<int>>, StringSink {
|
||||||
|
int _contentLength = 0;
|
||||||
|
late BytesBuilder _buf;
|
||||||
|
final Completer _done = Completer();
|
||||||
|
final LockableMockHttpHeaders _headers = LockableMockHttpHeaders();
|
||||||
|
Uri? _requestedUri;
|
||||||
|
late MockHttpSession _session;
|
||||||
|
final StreamController<Uint8List> _stream = StreamController<Uint8List>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
final List<Cookie> cookies = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpConnectionInfo connectionInfo =
|
||||||
|
MockHttpConnectionInfo(remoteAddress: InternetAddress.loopbackIPv4);
|
||||||
|
|
||||||
|
@override
|
||||||
|
MockHttpResponse response = MockHttpResponse(
|
||||||
|
contentLength: 0,
|
||||||
|
encoding: utf8,
|
||||||
|
persistentConnection: false,
|
||||||
|
reasonPhrase: '',
|
||||||
|
statusCode: 200);
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpSession get session => _session;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String method;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final Uri uri;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool persistentConnection = true;
|
||||||
|
|
||||||
|
/// [copyBuffer] corresponds to `copy` on the [BytesBuilder] constructor.
|
||||||
|
MockHttpRequest(this.method, this.uri,
|
||||||
|
{bool copyBuffer = true,
|
||||||
|
String? protocolVersion,
|
||||||
|
String? sessionId,
|
||||||
|
this.certificate,
|
||||||
|
this.persistentConnection = true}) {
|
||||||
|
_buf = BytesBuilder(copy: copyBuffer != false);
|
||||||
|
_session = MockHttpSession(id: sessionId ?? 'mock-http-session');
|
||||||
|
|
||||||
|
this.protocolVersion = protocolVersion ?? '1.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get contentLength => _contentLength;
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpHeaders get headers => _headers;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uri get requestedUri {
|
||||||
|
if (_requestedUri != null) {
|
||||||
|
return _requestedUri!;
|
||||||
|
} else {
|
||||||
|
return _requestedUri = Uri(
|
||||||
|
scheme: 'http',
|
||||||
|
host: 'example.com',
|
||||||
|
path: uri.path,
|
||||||
|
query: uri.query,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set requestedUri(Uri value) {
|
||||||
|
_requestedUri = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
late String protocolVersion;
|
||||||
|
|
||||||
|
@override
|
||||||
|
X509Certificate? certificate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(List<int> data) {
|
||||||
|
if (_done.isCompleted) {
|
||||||
|
throw StateError('Cannot add to closed MockHttpRequest.');
|
||||||
|
} else {
|
||||||
|
_headers.lock();
|
||||||
|
_contentLength += data.length;
|
||||||
|
_buf.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addError(error, [StackTrace? stackTrace]) {
|
||||||
|
if (_done.isCompleted) {
|
||||||
|
throw StateError('Cannot add to closed MockHttpRequest.');
|
||||||
|
} else {
|
||||||
|
_stream.addError(error, stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addStream(Stream<List<int>> stream) {
|
||||||
|
var c = Completer();
|
||||||
|
stream.listen(add, onError: addError, onDone: c.complete);
|
||||||
|
return c.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future close() async {
|
||||||
|
await flush();
|
||||||
|
_headers.lock();
|
||||||
|
scheduleMicrotask(_stream.close);
|
||||||
|
_done.complete();
|
||||||
|
return await _done.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future get done => _done.future;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
Future flush() async {
|
||||||
|
_contentLength += _buf.length;
|
||||||
|
_stream.add(_buf.takeBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(Object? obj) {
|
||||||
|
obj?.toString().codeUnits.forEach(writeCharCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeAll(Iterable objects, [String separator = '']) {
|
||||||
|
write(objects.join(separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeCharCode(int charCode) {
|
||||||
|
add([charCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeln([Object? obj = '']) {
|
||||||
|
write(obj ?? '');
|
||||||
|
add([$cr, $lf]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> any(bool Function(Uint8List element) test) {
|
||||||
|
return _stream.stream.any((List<int> e) {
|
||||||
|
return test(Uint8List.fromList(e));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> asBroadcastStream({
|
||||||
|
void Function(StreamSubscription<Uint8List> subscription)? onListen,
|
||||||
|
void Function(StreamSubscription<Uint8List> subscription)? onCancel,
|
||||||
|
}) {
|
||||||
|
return _stream.stream
|
||||||
|
.asBroadcastStream(onListen: onListen, onCancel: onCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<E> asyncExpand<E>(Stream<E>? Function(Uint8List event) convert) =>
|
||||||
|
_stream.stream.asyncExpand(convert);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<E> asyncMap<E>(FutureOr<E> Function(Uint8List event) convert) =>
|
||||||
|
_stream.stream.asyncMap(convert);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> contains(Object? needle) => _stream.stream.contains(needle);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> distinct(
|
||||||
|
[bool Function(Uint8List previous, Uint8List next)? equals]) =>
|
||||||
|
_stream.stream.distinct(equals);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<E> drain<E>([E? futureValue]) => _stream.stream.drain(futureValue);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> elementAt(int index) => _stream.stream.elementAt(index);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> every(bool Function(Uint8List element) test) =>
|
||||||
|
_stream.stream.every(test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<S> expand<S>(Iterable<S> Function(Uint8List value) convert) =>
|
||||||
|
_stream.stream.expand(convert);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> get first => _stream.stream.first;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> firstWhere(bool Function(Uint8List element) test,
|
||||||
|
{List<int> Function()? orElse}) =>
|
||||||
|
_stream.stream
|
||||||
|
.firstWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<S> fold<S>(
|
||||||
|
S initialValue, S Function(S previous, Uint8List element) combine) =>
|
||||||
|
_stream.stream.fold(initialValue, combine);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future forEach(void Function(Uint8List element) action) =>
|
||||||
|
_stream.stream.forEach(action);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> handleError(Function onError,
|
||||||
|
{bool Function(Object?)? test}) =>
|
||||||
|
_stream.stream.handleError(onError, test: test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isBroadcast => _stream.stream.isBroadcast;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> get isEmpty => _stream.stream.isEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> join([String separator = '']) =>
|
||||||
|
_stream.stream.join(separator);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> get last => _stream.stream.last;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> lastWhere(bool Function(Uint8List element) test,
|
||||||
|
{List<int> Function()? orElse}) =>
|
||||||
|
_stream.stream
|
||||||
|
.lastWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> get length => _stream.stream.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
StreamSubscription<Uint8List> listen(
|
||||||
|
void Function(Uint8List event)? onData, {
|
||||||
|
Function? onError,
|
||||||
|
void Function()? onDone,
|
||||||
|
bool? cancelOnError,
|
||||||
|
}) {
|
||||||
|
return _stream.stream.listen(
|
||||||
|
onData,
|
||||||
|
onError: onError,
|
||||||
|
onDone: onDone,
|
||||||
|
cancelOnError: cancelOnError == true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<S> map<S>(S Function(Uint8List event) convert) =>
|
||||||
|
_stream.stream.map(convert);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future pipe(StreamConsumer<List<int>> streamConsumer) =>
|
||||||
|
_stream.stream.cast<List<int>>().pipe(streamConsumer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> reduce(
|
||||||
|
List<int> Function(Uint8List previous, Uint8List element) combine) {
|
||||||
|
return _stream.stream.reduce((Uint8List previous, Uint8List element) {
|
||||||
|
return Uint8List.fromList(combine(previous, element));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> get single => _stream.stream.single;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> singleWhere(bool Function(Uint8List element) test,
|
||||||
|
{List<int> Function()? orElse}) =>
|
||||||
|
_stream.stream
|
||||||
|
.singleWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> skip(int count) => _stream.stream.skip(count);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> skipWhile(bool Function(Uint8List element) test) =>
|
||||||
|
_stream.stream.skipWhile(test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> take(int count) => _stream.stream.take(count);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> takeWhile(bool Function(Uint8List element) test) =>
|
||||||
|
_stream.stream.takeWhile(test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> timeout(Duration timeLimit,
|
||||||
|
{void Function(EventSink<Uint8List> sink)? onTimeout}) =>
|
||||||
|
_stream.stream.timeout(timeLimit, onTimeout: onTimeout);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Uint8List>> toList() => _stream.stream.toList();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Set<Uint8List>> toSet() => _stream.stream.toSet();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) =>
|
||||||
|
_stream.stream.cast<List<int>>().transform(streamTransformer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<Uint8List> where(bool Function(Uint8List event) test) =>
|
||||||
|
_stream.stream.where(test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<R> cast<R>() => Stream.castFrom<List<int>, R>(this);
|
||||||
|
}
|
151
packages/mock_request/lib/src/response.dart
Normal file
151
packages/mock_request/lib/src/response.dart
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io' hide BytesBuilder;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:charcode/ascii.dart';
|
||||||
|
import 'connection_info.dart';
|
||||||
|
import 'lockable_headers.dart';
|
||||||
|
|
||||||
|
class MockHttpResponse extends Stream<List<int>> implements HttpResponse {
|
||||||
|
BytesBuilder _buf = BytesBuilder();
|
||||||
|
bool _bufferOutput = true;
|
||||||
|
final Completer _done = Completer();
|
||||||
|
final LockableMockHttpHeaders _headers = LockableMockHttpHeaders();
|
||||||
|
final StreamController<List<int>> _stream = StreamController<List<int>>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
final List<Cookie> cookies = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpConnectionInfo connectionInfo =
|
||||||
|
MockHttpConnectionInfo(remoteAddress: InternetAddress.anyIPv4);
|
||||||
|
|
||||||
|
/// [copyBuffer] corresponds to `copy` on the [BytesBuilder] constructor.
|
||||||
|
MockHttpResponse(
|
||||||
|
{bool copyBuffer = true,
|
||||||
|
required this.statusCode,
|
||||||
|
required this.reasonPhrase,
|
||||||
|
required this.contentLength,
|
||||||
|
this.deadline,
|
||||||
|
required this.encoding,
|
||||||
|
required this.persistentConnection,
|
||||||
|
bool? bufferOutput}) {
|
||||||
|
_buf = BytesBuilder(copy: copyBuffer != false);
|
||||||
|
_bufferOutput = bufferOutput != false;
|
||||||
|
statusCode = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get bufferOutput => _bufferOutput;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set bufferOutput(bool value) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int contentLength;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Duration? deadline;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool persistentConnection;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String reasonPhrase;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int statusCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Encoding encoding;
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpHeaders get headers => _headers;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future get done => _done.future;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(List<int> data) {
|
||||||
|
if (_done.isCompleted) {
|
||||||
|
throw StateError('Cannot add to closed MockHttpResponse.');
|
||||||
|
} else {
|
||||||
|
_headers.lock();
|
||||||
|
if (_bufferOutput == true) {
|
||||||
|
_buf.add(data);
|
||||||
|
} else {
|
||||||
|
_stream.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addError(error, [StackTrace? stackTrace]) {
|
||||||
|
if (_done.isCompleted) {
|
||||||
|
throw StateError('Cannot add to closed MockHttpResponse.');
|
||||||
|
} else {
|
||||||
|
_stream.addError(error, stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addStream(Stream<List<int>> stream) {
|
||||||
|
var c = Completer();
|
||||||
|
stream.listen(add, onError: addError, onDone: c.complete);
|
||||||
|
return c.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future close() async {
|
||||||
|
_headers.lock();
|
||||||
|
await flush();
|
||||||
|
scheduleMicrotask(_stream.close);
|
||||||
|
_done.complete();
|
||||||
|
//return await _done.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Socket> detachSocket({bool writeHeaders = true}) {
|
||||||
|
throw UnsupportedError('MockHttpResponses have no socket to detach.');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future flush() async {
|
||||||
|
_stream.add(_buf.takeBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future redirect(Uri location,
|
||||||
|
{int status = HttpStatus.movedTemporarily}) async {
|
||||||
|
statusCode = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(Object? obj) {
|
||||||
|
obj?.toString().codeUnits.forEach(writeCharCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeAll(Iterable objects, [String separator = '']) {
|
||||||
|
write(objects.join(separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeCharCode(int charCode) {
|
||||||
|
add([charCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeln([Object? obj = '']) {
|
||||||
|
write(obj ?? '');
|
||||||
|
add([$cr, $lf]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
StreamSubscription<List<int>> listen(void Function(List<int> event)? onData,
|
||||||
|
{Function? onError, void Function()? onDone, bool? cancelOnError}) =>
|
||||||
|
_stream.stream.listen(onData,
|
||||||
|
onError: onError,
|
||||||
|
onDone: onDone,
|
||||||
|
cancelOnError: cancelOnError == true);
|
||||||
|
}
|
74
packages/mock_request/lib/src/session.dart
Normal file
74
packages/mock_request/lib/src/session.dart
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import 'dart:collection';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
class MockHttpSession extends MapBase implements HttpSession {
|
||||||
|
final Map _data = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String id;
|
||||||
|
|
||||||
|
MockHttpSession({required this.id});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get length => _data.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic operator [](Object? key) => _data[key];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void operator []=(key, value) {
|
||||||
|
_data[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addAll(Map other) => _data.addAll(other);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clear() {
|
||||||
|
_data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool containsKey(Object? key) => _data.containsKey(key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool containsValue(Object? value) => _data.containsValue(value);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void destroy() {
|
||||||
|
print('destroy() was called on a MockHttpSession, which does nothing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void forEach(void Function(dynamic, dynamic) action) {
|
||||||
|
_data.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isEmpty => _data.isEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isNew => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isNotEmpty => _data.isNotEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable get keys => _data.keys;
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic putIfAbsent(key, dynamic Function() ifAbsent) =>
|
||||||
|
_data.putIfAbsent(key, ifAbsent);
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic remove(Object? key) => _data.remove(key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable get values => _data.values;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set onTimeout(void Function() callback) {
|
||||||
|
print(
|
||||||
|
'An onTimeout callback was set on a MockHttpSession, which will do nothing.');
|
||||||
|
}
|
||||||
|
}
|
25
packages/mock_request/pubspec.yaml
Normal file
25
packages/mock_request/pubspec.yaml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
name: platform_mock_request
|
||||||
|
version: 9.0.0
|
||||||
|
description: Manufacture dart:io HttpRequests, HttpResponses, HttpHeaders, etc.
|
||||||
|
homepage: https://angel3-framework.web.app/
|
||||||
|
repository: https://github.com/dart-backend/angel/tree/master/packages/mock_request
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.3.0 <4.0.0'
|
||||||
|
dependencies:
|
||||||
|
charcode: ^1.3.0
|
||||||
|
dev_dependencies:
|
||||||
|
#angel3_framework: ^7.0.0
|
||||||
|
http: ^1.0.0
|
||||||
|
test: ^1.24.0
|
||||||
|
lints: ^4.0.0
|
||||||
|
# dependency_overrides:
|
||||||
|
# angel3_framework:
|
||||||
|
# path: ../framework
|
||||||
|
# angel3_route:
|
||||||
|
# path: ../route
|
||||||
|
# angel3_model:
|
||||||
|
# path: ../model
|
||||||
|
# angel3_http_exception:
|
||||||
|
# path: ../http_exception
|
||||||
|
# angel3_container:
|
||||||
|
# path: ../container/angel_container
|
69
packages/mock_request/test/all_test.dart
Normal file
69
packages/mock_request/test/all_test.dart
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//import 'dart:convert';
|
||||||
|
//import 'dart:io';
|
||||||
|
//import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
//import 'package:angel3_framework/http.dart';
|
||||||
|
//import 'package:angel3_mock_request/angel3_mock_request.dart';
|
||||||
|
//import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//var uri = Uri.parse('http://localhost:3000');
|
||||||
|
|
||||||
|
/*
|
||||||
|
var app = Angel()
|
||||||
|
..get('/foo', (req, res) => 'Hello, world!')
|
||||||
|
..post('/body',
|
||||||
|
(req, res) => req.parseBody().then((_) => req.bodyAsMap.length))
|
||||||
|
..get('/session', (req, res) async {
|
||||||
|
req.session?['foo'] = 'bar';
|
||||||
|
})
|
||||||
|
..get('/conn', (RequestContext req, res) {
|
||||||
|
return res.serialize(req.ip == InternetAddress.loopbackIPv4.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
var http = AngelHttp(app);
|
||||||
|
|
||||||
|
test('receive a response', () async {
|
||||||
|
var rq = MockHttpRequest('GET', uri.resolve('/foo'));
|
||||||
|
await rq.close();
|
||||||
|
await http.handleRequest(rq);
|
||||||
|
var rs = rq.response;
|
||||||
|
expect(rs.statusCode, equals(200));
|
||||||
|
expect(await rs.transform(utf8.decoder).join(),
|
||||||
|
equals(json.encode('Hello, world!')));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('send a body', () async {
|
||||||
|
var rq = MockHttpRequest('POST', uri.resolve('/body'));
|
||||||
|
rq
|
||||||
|
..headers.set(HttpHeaders.contentTypeHeader, ContentType.json.mimeType)
|
||||||
|
..write(json.encode({'foo': 'bar', 'bar': 'baz', 'baz': 'quux'}));
|
||||||
|
await rq.close();
|
||||||
|
await http.handleRequest(rq);
|
||||||
|
var rs = rq.response;
|
||||||
|
expect(rs.statusCode, equals(200));
|
||||||
|
expect(await rs.transform(utf8.decoder).join(), equals(json.encode(3)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('session', () async {
|
||||||
|
var rq = MockHttpRequest('GET', uri.resolve('/session'));
|
||||||
|
await rq.close();
|
||||||
|
await http.handleRequest(rq);
|
||||||
|
expect(rq.session.keys, contains('foo'));
|
||||||
|
expect(rq.session['foo'], equals('bar'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('connection info', () async {
|
||||||
|
var rq = MockHttpRequest('GET', uri.resolve('/conn'));
|
||||||
|
await rq.close();
|
||||||
|
await http.handleRequest(rq);
|
||||||
|
var rs = rq.response;
|
||||||
|
expect(await rs.transform(utf8.decoder).join(), equals(json.encode(true)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('requested uri', () {
|
||||||
|
var rq = MockHttpRequest('GET', uri.resolve('/mock'));
|
||||||
|
expect(rq.uri.path, '/mock');
|
||||||
|
expect(rq.requestedUri.toString(), 'http://example.com/mock');
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
Loading…
Reference in a new issue