All tests now passing
This commit is contained in:
parent
6dbccd2be6
commit
1b37e0a2a3
13 changed files with 294 additions and 95 deletions
|
@ -9,6 +9,7 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/test/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/test/route/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/test/router/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/test/server/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/web/hash/packages" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/web/packages" />
|
||||
|
|
6
.idea/runConfigurations/All_Server_Tests.xml
Normal file
6
.idea/runConfigurations/All_Server_Tests.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="All Server Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" folderName="Server Tests" singleton="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/test/server/all_tests.dart" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
|
@ -17,7 +17,7 @@ abstract class BrowserRouter extends Router {
|
|||
: new _PushStateRouter(listen: listen, root: root);
|
||||
}
|
||||
|
||||
BrowserRouter._([Route root]) : super(root);
|
||||
BrowserRouter._([Route root]) : super(root: root);
|
||||
|
||||
/// Calls `goTo` on the [Route] matching `path`.
|
||||
void go(String path, [Map params]);
|
||||
|
@ -37,7 +37,7 @@ class _BrowserRouterImpl extends Router implements BrowserRouter {
|
|||
@override
|
||||
Stream<Route> get onRoute => _onRoute.stream;
|
||||
|
||||
_BrowserRouterImpl({bool listen, Route root}) : super(root) {
|
||||
_BrowserRouterImpl({bool listen, Route root}) : super(root: root) {
|
||||
if (listen) this.listen();
|
||||
prepareAnchors();
|
||||
}
|
||||
|
|
|
@ -115,6 +115,15 @@ class Route {
|
|||
return result;
|
||||
}
|
||||
|
||||
/// Returns the [Route] instance that will respond to requests
|
||||
/// to the index of this instance's path.
|
||||
///
|
||||
/// May return `this`.
|
||||
Route get indexRoute {
|
||||
return children.firstWhere((r) => r.path.replaceAll(path, '').isEmpty,
|
||||
orElse: () => this);
|
||||
}
|
||||
|
||||
void _printDebug(msg) {
|
||||
if (debug) print(msg);
|
||||
}
|
||||
|
@ -157,6 +166,7 @@ class Route {
|
|||
/// The final child route is returned.
|
||||
factory Route.build(Pattern path,
|
||||
{Iterable<Route> children: const [],
|
||||
bool debug: false,
|
||||
Iterable handlers: const [],
|
||||
method: "GET",
|
||||
String name: null}) {
|
||||
|
@ -169,7 +179,11 @@ class Route {
|
|||
|
||||
if (segments.isEmpty) {
|
||||
return new Route('/',
|
||||
children: children, handlers: handlers, method: method, name: name);
|
||||
children: children,
|
||||
debug: debug,
|
||||
handlers: handlers,
|
||||
method: method,
|
||||
name: name);
|
||||
}
|
||||
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
|
@ -177,15 +191,15 @@ class Route {
|
|||
|
||||
if (i == segments.length - 1) {
|
||||
if (result == null) {
|
||||
result = new Route(segment);
|
||||
result = new Route(segment, debug: debug);
|
||||
} else {
|
||||
result = result.child(segment);
|
||||
result = result.child(segment, debug: debug);
|
||||
}
|
||||
} else {
|
||||
if (result == null) {
|
||||
result = new Route(segment, method: "*");
|
||||
result = new Route(segment, debug: debug, method: "*");
|
||||
} else {
|
||||
result = result.child(segment, method: "*");
|
||||
result = result.child(segment, debug: debug, method: "*");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,11 +209,11 @@ class Route {
|
|||
result._method = method;
|
||||
result._name = name;
|
||||
|
||||
return result;
|
||||
return result..debug = debug;
|
||||
}
|
||||
|
||||
/// Combines the paths and matchers of two [Route] instances, and creates a new instance.
|
||||
factory Route.join(Route parent, Route child) {
|
||||
factory Route.join(Route parent, Route child, {bool debug: false}) {
|
||||
final String path1 = parent.path
|
||||
.replaceAll(_rgxStart, '')
|
||||
.replaceAll(_rgxEnd, '')
|
||||
|
@ -217,7 +231,6 @@ class Route {
|
|||
|
||||
final route = new Route('$path1/$path2',
|
||||
children: child.children,
|
||||
debug: parent.debug || child.debug,
|
||||
handlers: child.handlers,
|
||||
method: child.method,
|
||||
name: child.name);
|
||||
|
@ -228,10 +241,29 @@ class Route {
|
|||
.._matcher = new RegExp('$pattern1$separator$pattern2')
|
||||
.._parent = parent
|
||||
.._stub = child.matcher);
|
||||
parent._printDebug(
|
||||
'Joined $path1 and $path2, produced stub ${route._stub.pattern}');
|
||||
|
||||
return route;
|
||||
parent._printDebug(
|
||||
"Joined '/$path1' and '/$path2', created stub: ${route._stub.pattern}");
|
||||
|
||||
return route..debug = parent.debug || child.debug || debug;
|
||||
}
|
||||
|
||||
Route _inherit(Route route) {
|
||||
/*
|
||||
final List<Route> _children = [];
|
||||
final List _handlers = [];
|
||||
RegExp _matcher;
|
||||
String _method;
|
||||
String _name;
|
||||
Route _parent;
|
||||
RegExp _parentResolver;
|
||||
String _path;
|
||||
String _pathified;
|
||||
RegExp _resolver;
|
||||
RegExp _stub;
|
||||
|
||||
*/
|
||||
return route.._parent = this;
|
||||
}
|
||||
|
||||
/// Calls [addChild] on all given routes.
|
||||
|
@ -241,7 +273,14 @@ class Route {
|
|||
|
||||
/// Adds the given route as a hierarchical child of this one.
|
||||
Route addChild(Route route, {bool join: true}) {
|
||||
Route created = join ? new Route.join(this, route) : route.._parent = this;
|
||||
Route created;
|
||||
|
||||
if (join) {
|
||||
created = new Route.join(this, route);
|
||||
} else {
|
||||
_children.add(created = route.._parent = this);
|
||||
}
|
||||
|
||||
return created..debug = debug;
|
||||
}
|
||||
|
||||
|
@ -251,11 +290,16 @@ class Route {
|
|||
/// Creates a hierarchical child of this route with the given path.
|
||||
Route child(Pattern path,
|
||||
{Iterable<Route> children: const [],
|
||||
bool debug: false,
|
||||
Iterable handlers: const [],
|
||||
String method: "GET",
|
||||
String name: null}) {
|
||||
final route = new Route.build(path,
|
||||
children: children, handlers: handlers, method: method, name: name);
|
||||
children: children,
|
||||
debug: debug,
|
||||
handlers: handlers,
|
||||
method: method,
|
||||
name: name);
|
||||
return addChild(route);
|
||||
}
|
||||
|
||||
|
@ -310,25 +354,39 @@ class Route {
|
|||
///
|
||||
/// Can be used to navigate a route hierarchy like a file system.
|
||||
Route resolve(String path, {bool filter(Route route), String fullPath}) {
|
||||
final _filter = filter ?? (_) => true;
|
||||
bool _filter(route) {
|
||||
if (filter == null) {
|
||||
_printDebug('No filter provided, returning true for $route');
|
||||
return true;
|
||||
} else {
|
||||
_printDebug('Running filter on $route');
|
||||
final result = filter(route);
|
||||
_printDebug('Filter result: $result');
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
final _fullPath = fullPath ?? path;
|
||||
|
||||
if ((path.isEmpty || path == '.') && _filter(this)) {
|
||||
if ((path.isEmpty || path == '.') && _filter(indexRoute)) {
|
||||
// Try to find index
|
||||
_printDebug('INDEX???');
|
||||
return children.firstWhere((r) => r.path.isEmpty, orElse: () => this);
|
||||
_printDebug('Empty path, resolving with indexRoute: $indexRoute');
|
||||
return indexRoute;
|
||||
} else if (path == '/') {
|
||||
return absoluteParent.resolve('');
|
||||
} else if (path.replaceAll(_straySlashes, '').isEmpty) {
|
||||
for (Route route in children) {
|
||||
final stub = route.path.replaceAll(this.path, '');
|
||||
|
||||
if ((stub == '/' || stub.isEmpty) && _filter(route)) return route;
|
||||
if ((stub == '/' || stub.isEmpty) && _filter(route))
|
||||
return route.resolve('');
|
||||
}
|
||||
|
||||
if (_filter(this))
|
||||
return this;
|
||||
else
|
||||
if (_filter(indexRoute)) {
|
||||
_printDebug(
|
||||
'Path "/$path" is technically empty, sending to indexRoute: $indexRoute');
|
||||
return indexRoute;
|
||||
} else
|
||||
return null;
|
||||
} else if (path == '..') {
|
||||
if (parent != null)
|
||||
|
@ -343,13 +401,16 @@ class Route {
|
|||
filter: _filter, fullPath: _fullPath);
|
||||
} else if (matcher.hasMatch(path.replaceAll(_straySlashes, '')) ||
|
||||
_resolver.hasMatch(path.replaceAll(_straySlashes, ''))) {
|
||||
return this;
|
||||
_printDebug(
|
||||
'Path "/$path" matched our matcher, sending to indexRoute: $indexRoute');
|
||||
return indexRoute;
|
||||
} else {
|
||||
final segments = path.split('/').where((str) => str.isNotEmpty).toList();
|
||||
_printDebug('Segments: $segments on "/${this.path}"');
|
||||
|
||||
if (segments.isEmpty) {
|
||||
return children.firstWhere((r) => r.path.isEmpty, orElse: () => this);
|
||||
_printDebug('Empty segments, sending to indexRoute: $indexRoute');
|
||||
return indexRoute;
|
||||
}
|
||||
|
||||
if (segments[0] == '..') {
|
||||
|
@ -366,12 +427,12 @@ class Route {
|
|||
for (Route route in children) {
|
||||
final subPath = '${this.path}/${segments[0]}';
|
||||
_printDebug(
|
||||
'seg0: ${segments[0]}, stub: ${route._stub.pattern}, path: $path, route.path: ${route.path}, route.matcher: ${route.matcher.pattern}, this.matcher: ${matcher.pattern}');
|
||||
'seg0: ${segments[0]}, stub: ${route._stub?.pattern}, path: $path, route.path: ${route.path}, route.matcher: ${route.matcher.pattern}, this.matcher: ${matcher.pattern}');
|
||||
|
||||
if (route.match(subPath) != null ||
|
||||
route._resolver.firstMatch(subPath) != null) {
|
||||
if (segments.length == 1 && _filter(route))
|
||||
return route;
|
||||
return route.resolve('');
|
||||
else {
|
||||
return route.resolve(segments.skip(1).join('/'),
|
||||
filter: _filter,
|
||||
|
@ -380,8 +441,14 @@ class Route {
|
|||
_fullPath.replaceAll(_straySlashes, ''));
|
||||
}
|
||||
} else if (route._stub != null && route._stub.hasMatch(segments[0])) {
|
||||
_printDebug('MAYBE STUB?');
|
||||
return route;
|
||||
if (segments.length == 1) {
|
||||
_printDebug('Stub perhaps matches');
|
||||
return route.resolve('');
|
||||
} else {
|
||||
_printDebug(
|
||||
'Maybe stub matches. Sending remaining segments to $route');
|
||||
return route.resolve(segments.skip(1).join('/'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,38 +472,11 @@ class Route {
|
|||
(child.match(_fullPath) != null ||
|
||||
child._resolver.firstMatch(_fullPath) != null) &&
|
||||
_filter(child)) {
|
||||
return child;
|
||||
return child.resolve('');
|
||||
}
|
||||
}
|
||||
|
||||
_printDebug('No subpath match: $subPath');
|
||||
} else
|
||||
_printDebug('Nope: $_parentResolver');
|
||||
}
|
||||
|
||||
/*
|
||||
// Try to fill params
|
||||
for (Route route in children) {
|
||||
final params = parseParameters(_fullPath);
|
||||
final _filledPath = makeUri(params);
|
||||
_printDebug(
|
||||
'Trying to match filled $_filledPath for ${route.path} on ${this.path}');
|
||||
if ((route.match(_filledPath) != null ||
|
||||
route._resolver.firstMatch(_filledPath) != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
else if ((route.match(_filledPath) != null ||
|
||||
route._resolver.firstMatch(_filledPath) != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
else if ((route.match('/$_filledPath') != null ||
|
||||
route._resolver.firstMatch('/$_filledPath') != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
else {
|
||||
_printDebug('Failed for ${route.matcher} when given $_filledPath');
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Try to match the whole route, if nothing else works
|
||||
for (Route route in children) {
|
||||
|
@ -445,18 +485,20 @@ class Route {
|
|||
if ((route.match(_fullPath) != null ||
|
||||
route._resolver.firstMatch(_fullPath) != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
return route.resolve('');
|
||||
else if ((route.match(_fullPath) != null ||
|
||||
route._resolver.firstMatch(_fullPath) != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
return route.resolve('');
|
||||
else if ((route.match('/$_fullPath') != null ||
|
||||
route._resolver.firstMatch('/$_fullPath') != null) &&
|
||||
_filter(route))
|
||||
return route;
|
||||
else {
|
||||
_printDebug('Failed for ${route.matcher} when given $_fullPath');
|
||||
}
|
||||
_filter(route)) return route.resolve('');
|
||||
}
|
||||
|
||||
// Lastly, check to see if we have an index route to resolve with
|
||||
if (indexRoute != this) {
|
||||
_printDebug('Forwarding "/$path" to indexRoute');
|
||||
return indexRoute.resolve(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -6,6 +6,8 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
|
|||
|
||||
/// An abstraction over complex [Route] trees. Use this instead of the raw API. :)
|
||||
class Router extends Extensible {
|
||||
Route _root;
|
||||
|
||||
/// Set to `true` to print verbose debug output when interacting with this route.
|
||||
bool debug = false;
|
||||
|
||||
|
@ -13,15 +15,16 @@ class Router extends Extensible {
|
|||
Map<String, dynamic> requestMiddleware = {};
|
||||
|
||||
/// The single [Route] that serves as the root of the hierarchy.
|
||||
final Route root;
|
||||
Route get root => _root;
|
||||
|
||||
/// Provide a `root` to make this Router revolve around a pre-defined route.
|
||||
/// Not recommended.
|
||||
Router([Route root]) : this.root = root ?? new _RootRoute();
|
||||
Router({this.debug: false, Route root}) {
|
||||
_root = (_root = root ?? new _RootRoute())..debug = debug;
|
||||
}
|
||||
|
||||
void _printDebug(msg) {
|
||||
if (debug)
|
||||
_printDebug(msg);
|
||||
if (debug) print(msg);
|
||||
}
|
||||
|
||||
/// Adds a route that responds to the given path
|
||||
|
@ -36,9 +39,10 @@ class Router extends Extensible {
|
|||
..add(handler);
|
||||
|
||||
if (path is RegExp) {
|
||||
return root.child(path, handlers: handlers, method: method);
|
||||
return root.child(path, debug: debug, handlers: handlers, method: method);
|
||||
} else if (path.toString().replaceAll(_straySlashes, '').isEmpty) {
|
||||
return root.child(path.toString(), handlers: handlers, method: method);
|
||||
return root.child(path.toString(),
|
||||
debug: debug, handlers: handlers, method: method);
|
||||
} else {
|
||||
var segments = path
|
||||
.toString()
|
||||
|
@ -48,9 +52,9 @@ class Router extends Extensible {
|
|||
Route result;
|
||||
|
||||
if (segments.isEmpty) {
|
||||
return new Route('/', handlers: handlers, method: method);
|
||||
return new Route('/', debug: debug, handlers: handlers, method: method)
|
||||
..debug = debug;
|
||||
} else {
|
||||
_printDebug('Want ${segments[0]}');
|
||||
result = resolve(segments[0]);
|
||||
|
||||
if (result != null) {
|
||||
|
@ -67,7 +71,9 @@ class Router extends Extensible {
|
|||
result = existing;
|
||||
}
|
||||
} while (existing != null);
|
||||
} else throw new RoutingException("Cannot overwrite existing route '${segments[0]}'.");
|
||||
} else
|
||||
throw new RoutingException(
|
||||
"Cannot overwrite existing route '${segments[0]}'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,15 +82,17 @@ class Router extends Extensible {
|
|||
|
||||
if (i == segments.length - 1) {
|
||||
if (result == null) {
|
||||
result = root.child(segment, handlers: handlers, method: method);
|
||||
result = root.child(segment,
|
||||
debug: debug, handlers: handlers, method: method);
|
||||
} else {
|
||||
result = result.child(segment, handlers: handlers, method: method);
|
||||
result = result.child(segment,
|
||||
debug: debug, handlers: handlers, method: method);
|
||||
}
|
||||
} else {
|
||||
if (result == null) {
|
||||
result = root.child(segment, method: "*");
|
||||
result = root.child(segment, debug: debug, method: "*");
|
||||
} else {
|
||||
result = result.child(segment, method: "*");
|
||||
result = result.child(segment, debug: debug, method: "*");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +113,8 @@ class Router extends Extensible {
|
|||
|
||||
if (route == root)
|
||||
buf.write('(root) ${route.method} ');
|
||||
else buf.write('- ${route.method} ');
|
||||
else
|
||||
buf.write('- ${route.method} ');
|
||||
|
||||
final p =
|
||||
replace != null ? route.path.replaceAll(replace, '') : route.path;
|
||||
|
@ -143,7 +152,7 @@ class Router extends Extensible {
|
|||
String namespace: null}) {
|
||||
final route =
|
||||
root.child(path, handlers: middleware, method: method, name: name);
|
||||
final router = new Router(route);
|
||||
final router = new Router(root: route);
|
||||
callback(router);
|
||||
|
||||
// Let's copy middleware, heeding the optional middleware namespace.
|
||||
|
@ -191,7 +200,7 @@ class Router extends Extensible {
|
|||
copiedMiddleware[middlewareName];
|
||||
}
|
||||
|
||||
root.child(path).addChild(router.root);
|
||||
root.child(path, debug: debug).addChild(router.root);
|
||||
}
|
||||
|
||||
/// Adds a route that responds to any request matching the given path.
|
||||
|
@ -236,9 +245,8 @@ class Router extends Extensible {
|
|||
}
|
||||
|
||||
class _RootRoute extends Route {
|
||||
_RootRoute():super("/", name: "<root>");
|
||||
|
||||
_RootRoute() : super("/", name: "<root>");
|
||||
|
||||
@override
|
||||
String toString() => "ROOT";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ author: Tobe O <thosakwe@gmail.com>
|
|||
homepage: https://github.com/angel-dart/angel_route
|
||||
dev_dependencies:
|
||||
browser: ">=0.10.0 < 0.11.0"
|
||||
http: ">=0.11.3 <0.12.0"
|
||||
test: ">=0.12.15 <0.13.0"
|
8
test/all_tests.browser.dart
Normal file
8
test/all_tests.browser.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'route/all_tests.dart' as route;
|
||||
import 'router/all_tests.dart' as router;
|
||||
|
||||
main() {
|
||||
group('route', route.main);
|
||||
group('router', router.main);
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'route/all_tests.dart' as route;
|
||||
import 'router/all_tests.dart' as router;
|
||||
import 'server/all_tests.dart' as server;
|
||||
|
||||
main() {
|
||||
group('route', route.main);
|
||||
group('router', router.main);
|
||||
group('server', server.main);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<title>Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="all_tests.dart" type="application/dart"></script>
|
||||
<script src="all_tests.browser.dart" type="application/dart"></script>
|
||||
<script src="packages/browser/dart.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -7,7 +7,7 @@ main() {
|
|||
final bar = fooById.child('bar');
|
||||
final baz = bar.child('//////baz//////', handlers: ['hello', 'world']);
|
||||
final bazById = baz.child(':bazId([A-Za-z]+)');
|
||||
new Router(foo).dumpTree();
|
||||
new Router(root: foo).dumpTree();
|
||||
|
||||
test('matching', () {
|
||||
expect(fooById.children.length, equals(1));
|
||||
|
@ -54,7 +54,7 @@ main() {
|
|||
|
||||
expect(bar.resolve('..'), equals(fooById));
|
||||
|
||||
new Router(bar.parent).dumpTree(header: "POOP");
|
||||
new Router(root: bar.parent).dumpTree(header: "POOP");
|
||||
expect(bar.parent.resolve('bar/baz'), equals(baz));
|
||||
expect(bar.resolve('/2/bar/baz'), equals(baz));
|
||||
expect(bar.resolve('../bar'), equals(bar));
|
||||
|
|
|
@ -9,7 +9,8 @@ main() {
|
|||
final router = new Router();
|
||||
final indexRoute = router.get('/', () => ':)');
|
||||
final fizz = router.post('/user/fizz', null);
|
||||
final deleteUserById = router.delete('/user/:id/detail', (id) => num.parse(id));
|
||||
final deleteUserById =
|
||||
router.delete('/user/:id/detail', (id) => num.parse(id));
|
||||
|
||||
Route lower;
|
||||
final letters = router.group('/letter///', (router) {
|
||||
|
@ -29,6 +30,7 @@ main() {
|
|||
});
|
||||
|
||||
group('fallback', fallback.main);
|
||||
test('group & use', use.main);
|
||||
|
||||
test('hierarchy', () {
|
||||
expect(lower.absoluteParent, equals(router.root));
|
||||
|
@ -45,7 +47,4 @@ main() {
|
|||
expect(router.resolve('letter/a/lower'), equals(lower));
|
||||
expect(router.resolve('letter/2/lower'), isNull);
|
||||
});
|
||||
|
||||
|
||||
test('use', use.main);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,35 @@
|
|||
import 'package:angel_route/angel_route.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final String ARTIFICIAL_INDEX = 'artificial index';
|
||||
|
||||
tattle(x) => 'This ${x.runtimeType}.debug = ${x.debug}';
|
||||
tattleAll(x) => x.map(tattle).join('\n');
|
||||
|
||||
main() {
|
||||
final parent = new Router()..debug = true;
|
||||
final child = new Router()..debug = true;
|
||||
final a = child.get('a', ['c']);
|
||||
final parent = new Router(debug: true);
|
||||
final child = new Router(debug: true);
|
||||
Route a, b, c;
|
||||
|
||||
a = child.get('a', ['c']);
|
||||
child.group('b', (router) {
|
||||
b = router.get('/', ARTIFICIAL_INDEX);
|
||||
c = router.post('c', 'Hello nested');
|
||||
});
|
||||
|
||||
parent.use('child', child);
|
||||
parent.dumpTree();
|
||||
parent.dumpTree(header: tattleAll([parent, child, a]));
|
||||
|
||||
group('no params', () {
|
||||
test('resolve', () {
|
||||
expect(child.resolve('a'), equals(a));
|
||||
expect(child.resolve('b'), equals(b));
|
||||
expect(child.resolve('b/c'), equals(c));
|
||||
|
||||
expect(parent.resolve('child/a'), equals(a));
|
||||
expect(parent.resolve('a'), isNull);
|
||||
expect(parent.resolve('child/b'), equals(b));
|
||||
expect(parent.resolve('child/b/c'), equals(c));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
114
test/server/all_tests.dart
Normal file
114
test/server/all_tests.dart
Normal file
|
@ -0,0 +1,114 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:io';
|
||||
import 'package:angel_route/angel_route.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
typedef Future<bool> RequestHandler(HttpRequest request);
|
||||
|
||||
final String MIDDLEWARE_GREETING = 'Hi, I am a middleware!';
|
||||
|
||||
main() {
|
||||
http.Client client;
|
||||
Router router;
|
||||
HttpServer server;
|
||||
String url;
|
||||
|
||||
setUp(() async {
|
||||
client = new http.Client();
|
||||
router = new Router(debug: true);
|
||||
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
|
||||
url = 'http://${server.address.address}:${server.port}';
|
||||
|
||||
server.listen((request) async {
|
||||
final resolved = router.resolve(request.uri.toString(), (route) {
|
||||
print(
|
||||
'$route matches ${request.method} ${request.uri}? ${route.method == request.method || route.method == '*'}');
|
||||
return route.method == request.method || route.method == '*';
|
||||
});
|
||||
|
||||
if (resolved == null) {
|
||||
request.response.statusCode = 404;
|
||||
request.response.write('404 Not Found');
|
||||
await request.response.close();
|
||||
} else {
|
||||
// Easy middleware pipeline
|
||||
for (final handler in resolved.handlerSequence) {
|
||||
if (handler is String) {
|
||||
if (!await router.requestMiddleware[handler](request)) break;
|
||||
} else if (!await handler(request)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await request.response.close();
|
||||
}
|
||||
});
|
||||
|
||||
router.get('foo', (HttpRequest request) async {
|
||||
request.response.write('bar');
|
||||
return false;
|
||||
});
|
||||
|
||||
Route square;
|
||||
|
||||
square = router.post('square/:num([0-9]+)', (HttpRequest request) async {
|
||||
final params = square.parseParameters(request.uri.toString());
|
||||
final squared = math.pow(params['num'], 2);
|
||||
request.response.statusCode = squared;
|
||||
request.response.write(squared);
|
||||
return false;
|
||||
});
|
||||
|
||||
router.group('todos', (router) {
|
||||
router.get('/', (HttpRequest request) async {
|
||||
print('TODO INDEX???');
|
||||
request.response.write([]);
|
||||
return false;
|
||||
});
|
||||
}, middleware: [
|
||||
(HttpRequest request) async {
|
||||
request.response.write(MIDDLEWARE_GREETING);
|
||||
return true;
|
||||
}
|
||||
]);
|
||||
|
||||
router.dumpTree();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
client.close();
|
||||
client = null;
|
||||
router = null;
|
||||
url = null;
|
||||
await server.close();
|
||||
});
|
||||
|
||||
group('group', () {
|
||||
test('todo index', () async {
|
||||
final response = await client.get('$url/todos');
|
||||
expect(response.statusCode, equals(200));
|
||||
expect(response.body, equals('$MIDDLEWARE_GREETING[]'));
|
||||
});
|
||||
});
|
||||
|
||||
group('top-level route', () {
|
||||
test('no params', () async {
|
||||
final response = await client.get('$url/foo');
|
||||
expect(response.statusCode, equals(200));
|
||||
expect(response.body, equals('bar'));
|
||||
});
|
||||
|
||||
test('with params', () async {
|
||||
final response = await client.post('$url/square/16');
|
||||
expect(response.statusCode, equals(256));
|
||||
expect(response.body, equals(response.statusCode.toString()));
|
||||
});
|
||||
|
||||
test('throw 404', () async {
|
||||
final response = await client.get('$url/abc');
|
||||
expect(response.statusCode, equals(404));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue