2019-04-10 17:52:45 +00:00
|
|
|
import 'dart:async';
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
2021-05-14 10:34:09 +00:00
|
|
|
import 'package:angel3_framework/angel3_framework.dart';
|
|
|
|
import 'package:angel3_framework/http.dart';
|
|
|
|
import 'package:angel3_mock_request/angel3_mock_request.dart';
|
2019-04-10 17:52:45 +00:00
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
var app = Angel();
|
|
|
|
var http = AngelHttp(app);
|
|
|
|
|
|
|
|
Future<RequestContext> request(
|
2019-04-11 02:37:05 +00:00
|
|
|
{bool asJson = true,
|
|
|
|
bool parse = true,
|
2021-03-20 08:11:18 +00:00
|
|
|
Map<String, dynamic>? bodyFields,
|
|
|
|
List? bodyList}) async {
|
|
|
|
var rq =
|
|
|
|
MockHttpRequest('POST', Uri(path: '/'), persistentConnection: false);
|
2019-04-10 17:52:45 +00:00
|
|
|
|
|
|
|
if (bodyFields != null) {
|
|
|
|
if (asJson) {
|
|
|
|
rq
|
|
|
|
..headers.contentType = ContentType('application', 'json')
|
|
|
|
..write(json.encode(bodyFields));
|
|
|
|
} else {
|
|
|
|
var b = StringBuffer();
|
|
|
|
var i = 0;
|
|
|
|
for (var entry in bodyFields.entries) {
|
|
|
|
if (i++ > 0) b.write('&');
|
|
|
|
b.write(entry.key);
|
|
|
|
b.write('=');
|
|
|
|
b.write(Uri.encodeComponent(entry.value.toString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
rq
|
|
|
|
..headers.contentType =
|
|
|
|
ContentType('application', 'x-www-form-urlencoded')
|
|
|
|
..write(json.encode(b.toString()));
|
|
|
|
}
|
|
|
|
} else if (bodyList != null) {
|
|
|
|
rq
|
|
|
|
..headers.contentType = ContentType('application', 'json')
|
|
|
|
..write(json.encode(bodyList));
|
|
|
|
}
|
|
|
|
|
|
|
|
await rq.close();
|
|
|
|
var req = await http.createRequestContext(rq, rq.response);
|
|
|
|
if (parse) await req.parseBody();
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
|
|
|
test('parses json maps', () async {
|
|
|
|
var req = await request(bodyFields: {'hello': 'world'});
|
|
|
|
expect(req.bodyAsObject, TypeMatcher<Map<String, dynamic>>());
|
|
|
|
expect(req.bodyAsMap, {'hello': 'world'});
|
|
|
|
});
|
|
|
|
|
|
|
|
test('parses json lists', () async {
|
|
|
|
var req = await request(bodyList: ['foo', 'bar']);
|
|
|
|
expect(req.bodyAsObject, TypeMatcher<List>());
|
|
|
|
expect(req.bodyAsList, ['foo', 'bar']);
|
|
|
|
});
|
|
|
|
|
2019-10-12 14:22:36 +00:00
|
|
|
test('deserializeBody', () async {
|
|
|
|
var req = await request(
|
|
|
|
asJson: true, bodyFields: {'text': 'Hey', 'complete': false});
|
|
|
|
var todo = await req.deserializeBody(Todo.fromMap);
|
|
|
|
expect(todo.text, 'Hey');
|
|
|
|
expect(todo.completed, false);
|
|
|
|
});
|
|
|
|
|
2019-10-12 14:24:54 +00:00
|
|
|
test('decodeBody', () async {
|
|
|
|
var req = await request(
|
|
|
|
asJson: true, bodyFields: {'text': 'Hey', 'complete': false});
|
|
|
|
var todo = await req.decodeBody(TodoCodec());
|
|
|
|
expect(todo.text, 'Hey');
|
|
|
|
expect(todo.completed, false);
|
|
|
|
});
|
|
|
|
|
2019-04-10 17:52:45 +00:00
|
|
|
test('throws when body has not been parsed', () async {
|
|
|
|
var req = await request(parse: false);
|
|
|
|
expect(() => req.bodyAsObject, throwsStateError);
|
|
|
|
expect(() => req.bodyAsMap, throwsStateError);
|
|
|
|
expect(() => req.bodyAsList, throwsStateError);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('can set body object exactly once', () async {
|
|
|
|
var req = await request(parse: false);
|
|
|
|
req.bodyAsObject = 23;
|
|
|
|
expect(req.bodyAsObject, 23);
|
|
|
|
expect(() => req.bodyAsObject = {45.6: '34'}, throwsStateError);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('can set body map exactly once', () async {
|
|
|
|
var req = await request(parse: false);
|
|
|
|
req.bodyAsMap = {'hey': 'yes'};
|
|
|
|
expect(req.bodyAsMap, {'hey': 'yes'});
|
|
|
|
expect(() => req.bodyAsMap = {'hm': 'ok'}, throwsStateError);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('can set body list exactly once', () async {
|
|
|
|
var req = await request(parse: false);
|
|
|
|
req.bodyAsList = [
|
|
|
|
{'hey': 'yes'}
|
|
|
|
];
|
|
|
|
expect(req.bodyAsList, [
|
|
|
|
{'hey': 'yes'}
|
|
|
|
]);
|
|
|
|
expect(
|
|
|
|
() => req.bodyAsList = [
|
|
|
|
{'hm': 'ok'}
|
|
|
|
],
|
|
|
|
throwsStateError);
|
|
|
|
});
|
|
|
|
}
|
2019-10-12 14:22:36 +00:00
|
|
|
|
|
|
|
class Todo {
|
2021-03-20 08:11:18 +00:00
|
|
|
String? text;
|
|
|
|
bool? completed;
|
2019-10-12 14:22:36 +00:00
|
|
|
|
|
|
|
Todo({this.text, this.completed});
|
|
|
|
|
2021-03-20 08:11:18 +00:00
|
|
|
static Todo fromMap(Map? m) =>
|
|
|
|
Todo(text: m!['text'] as String?, completed: m['complete'] as bool?);
|
2019-10-12 14:22:36 +00:00
|
|
|
}
|
2019-10-12 14:24:54 +00:00
|
|
|
|
2021-03-20 08:11:18 +00:00
|
|
|
class TodoCodec extends Codec<Todo, Map?> {
|
2019-10-12 14:24:54 +00:00
|
|
|
@override
|
|
|
|
Converter<Map, Todo> get decoder => TodoDecoder();
|
|
|
|
|
|
|
|
@override
|
|
|
|
Converter<Todo, Map> get encoder => throw UnsupportedError('no encoder');
|
|
|
|
}
|
|
|
|
|
|
|
|
class TodoDecoder extends Converter<Map, Todo> {
|
|
|
|
@override
|
|
|
|
Todo convert(Map input) => Todo.fromMap(input);
|
|
|
|
}
|