add(angel3): adding re-branded angel3 mock_request package

This commit is contained in:
Patrick Stewart 2024-09-22 18:45:32 -07:00
parent 9148934aa6
commit d884105ded
16 changed files with 1127 additions and 0 deletions

71
packages/mock_request/.gitignore vendored Normal file
View 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

View 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.

View 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

View 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.

View 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.

View file

@ -0,0 +1 @@
include: package:lints/recommended.yaml

View 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();
}

View 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';

View 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});
}

View 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;
}
}

View 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);
}
}
}

View 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);
}

View 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);
}

View 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.');
}
}

View 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

View 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');
});
*/
}