Index: utils/tests/pub/curl_client_test.dart |
diff --git a/utils/tests/pub/curl_client_test.dart b/utils/tests/pub/curl_client_test.dart |
index 5c94a72b0d1dcf66d32d622bec0758722e929bbf..c040c2db66e04f9b26d2388ba44fdffe201cf292 100644 |
--- a/utils/tests/pub/curl_client_test.dart |
+++ b/utils/tests/pub/curl_client_test.dart |
@@ -6,14 +6,210 @@ library curl_client_test; |
import 'dart:io'; |
import 'dart:isolate'; |
+import 'dart:json'; |
import 'dart:uri'; |
import '../../../pkg/unittest/lib/unittest.dart'; |
import '../../../pkg/http/lib/http.dart' as http; |
-import '../../../pkg/http/test/utils.dart'; |
import '../../pub/curl_client.dart'; |
import '../../pub/io.dart'; |
+// TODO(rnystrom): All of the code from here to the "---..." line was copied |
+// from pkg/http/test/utils.dart and pkg/http/lib/src/utils.dart. It's copied |
+// here because http/test/utils.dart is now using "package:" imports and this |
+// is not. You cannot mix those because you end up with duplicate copies of the |
+// same library in memory. Since curl_client is going away soon anyway, I'm |
+// just copying the code here. Delete all of this when curl client is removed. |
+ |
+/// Returns the [Encoding] that corresponds to [charset]. Throws a |
+/// [FormatException] if no [Encoding] was found that corresponds to [charset]. |
+/// [charset] may not be null. |
+Encoding requiredEncodingForCharset(String charset) { |
+ var encoding = _encodingForCharset(charset); |
+ if (encoding != null) return encoding; |
+ throw new FormatException('Unsupported encoding "$charset".'); |
+} |
+ |
+/// Returns the [Encoding] that corresponds to [charset]. Returns null if no |
+/// [Encoding] was found that corresponds to [charset]. [charset] may not be |
+/// null. |
+Encoding _encodingForCharset(String charset) { |
+ charset = charset.toLowerCase(); |
+ if (charset == 'ascii' || charset == 'us-ascii') return Encoding.ASCII; |
+ if (charset == 'utf-8') return Encoding.UTF_8; |
+ if (charset == 'iso-8859-1') return Encoding.ISO_8859_1; |
+ return null; |
+} |
+ |
+/// Converts [bytes] into a [String] according to [encoding]. |
+String decodeString(List<int> bytes, Encoding encoding) { |
+ // TODO(nweiz): implement this once issue 6284 is fixed. |
+ return new String.fromCharCodes(bytes); |
+} |
+ |
+/// The current server instance. |
+HttpServer _server; |
+ |
+/// The URL for the current server instance. |
+Uri get serverUrl => new Uri.fromString('http://localhost:${_server.port}'); |
+ |
+/// A dummy URL for constructing requests that won't be sent. |
+Uri get dummyUrl => new Uri.fromString('http://dartlang.org/'); |
+ |
+/// Starts a new HTTP server. |
+void startServer() { |
+ _server = new HttpServer(); |
+ |
+ _server.addRequestHandler((request) => request.path == '/error', |
+ (request, response) { |
+ response.statusCode = 400; |
+ response.contentLength = 0; |
+ response.outputStream.close(); |
+ }); |
+ |
+ _server.addRequestHandler((request) => request.path == '/loop', |
+ (request, response) { |
+ var n = int.parse(new Uri.fromString(request.uri).query); |
+ response.statusCode = 302; |
+ response.headers.set('location', |
+ serverUrl.resolve('/loop?${n + 1}').toString()); |
+ response.contentLength = 0; |
+ response.outputStream.close(); |
+ }); |
+ |
+ _server.addRequestHandler((request) => request.path == '/redirect', |
+ (request, response) { |
+ response.statusCode = 302; |
+ response.headers.set('location', serverUrl.resolve('/').toString()); |
+ response.contentLength = 0; |
+ response.outputStream.close(); |
+ }); |
+ |
+ _server.defaultRequestHandler = (request, response) { |
+ consumeInputStream(request.inputStream).then((requestBodyBytes) { |
+ response.statusCode = 200; |
+ response.headers.contentType = new ContentType("application", "json"); |
+ |
+ var requestBody; |
+ if (requestBodyBytes.isEmpty) { |
+ requestBody = null; |
+ } else if (request.headers.contentType.charset != null) { |
+ var encoding = requiredEncodingForCharset( |
+ request.headers.contentType.charset); |
+ requestBody = decodeString(requestBodyBytes, encoding); |
+ } else { |
+ requestBody = requestBodyBytes; |
+ } |
+ |
+ var content = { |
+ 'method': request.method, |
+ 'path': request.path, |
+ 'headers': <String>{} |
+ }; |
+ if (requestBody != null) content['body'] = requestBody; |
+ request.headers.forEach((name, values) { |
+ // These headers are automatically generated by dart:io, so we don't |
+ // want to test them here. |
+ if (name == 'cookie' || name == 'host') return; |
+ |
+ content['headers'][name] = values; |
+ }); |
+ |
+ var outputEncoding; |
+ var encodingName = request.queryParameters['response-encoding']; |
+ if (encodingName != null) { |
+ outputEncoding = requiredEncodingForCharset(encodingName); |
+ } else { |
+ outputEncoding = Encoding.ASCII; |
+ } |
+ |
+ var body = JSON.stringify(content); |
+ response.contentLength = body.length; |
+ response.outputStream.writeString(body, outputEncoding); |
+ response.outputStream.close(); |
+ }); |
+ }; |
+ |
+ _server.listen("127.0.0.1", 0); |
+} |
+ |
+/// Stops the current HTTP server. |
+void stopServer() { |
+ _server.close(); |
+ _server = null; |
+} |
+ |
+/// A matcher that matches JSON that parses to a value that matches the inner |
+/// matcher. |
+Matcher parse(matcher) => new _Parse(matcher); |
+ |
+class _Parse extends BaseMatcher { |
+ final Matcher _matcher; |
+ |
+ _Parse(this._matcher); |
+ |
+ bool matches(item, MatchState matchState) { |
+ if (item is! String) return false; |
+ |
+ var parsed; |
+ try { |
+ parsed = JSON.parse(item); |
+ } catch (e) { |
+ return false; |
+ } |
+ |
+ return _matcher.matches(parsed, matchState); |
+ } |
+ |
+ Description describe(Description description) { |
+ return description.add('parses to a value that ') |
+ .addDescriptionOf(_matcher); |
+ } |
+} |
+ |
+// TODO(nweiz): remove this once it's built in to unittest |
+/// A matcher for StateErrors. |
+const isStateError = const _StateError(); |
+ |
+/// A matcher for functions that throw StateError. |
+const Matcher throwsStateError = |
+ const Throws(isStateError); |
+ |
+class _StateError extends TypeMatcher { |
+ const _StateError() : super("StateError"); |
+ bool matches(item, MatchState matchState) => item is StateError; |
+} |
+ |
+/// A matcher for HttpExceptions. |
+const isHttpException = const _HttpException(); |
+ |
+/// A matcher for functions that throw HttpException. |
+const Matcher throwsHttpException = |
+ const Throws(isHttpException); |
+ |
+class _HttpException extends TypeMatcher { |
+ const _HttpException() : super("HttpException"); |
+ bool matches(item, MatchState matchState) => item is HttpException; |
+} |
+ |
+/// A matcher for RedirectLimitExceededExceptions. |
+const isRedirectLimitExceededException = |
+ const _RedirectLimitExceededException(); |
+ |
+/// A matcher for functions that throw RedirectLimitExceededException. |
+const Matcher throwsRedirectLimitExceededException = |
+ const Throws(isRedirectLimitExceededException); |
+ |
+class _RedirectLimitExceededException extends TypeMatcher { |
+ const _RedirectLimitExceededException() : |
+ super("RedirectLimitExceededException"); |
+ |
+ bool matches(item, MatchState matchState) => |
+ item is RedirectLimitExceededException; |
+} |
+ |
+// ---------------------------------------------------------------------------- |
+ |
void main() { |
setUp(startServer); |
tearDown(stopServer); |