import 'dart:convert'; import 'package:http/http.dart' as http; /// Records requests and returns canned responses for Alpaca client unit tests. class MockHttpClient extends http.BaseClient { MockHttpClient({Map? responses}) : _responses = responses ?? {}; final Map _responses; final List requests = []; /// Captured request bodies indexed by request order in [requests]. final List capturedBodies = []; void whenGet(String pathSuffix, http.Response response) { _responses[pathSuffix] = _MatchedResponse(method: 'GET', response: response); } void whenGetJson(String pathSuffix, Map body, {int statusCode = 200}) { whenGet( pathSuffix, http.Response(jsonEncode(body), statusCode, headers: { 'content-type': 'application/json', }), ); } void whenPost(String pathSuffix, http.Response response) { _responses['POST:$pathSuffix'] = _MatchedResponse(method: 'POST', response: response); } void whenPostJson(String pathSuffix, Map body, {int statusCode = 200}) { whenPost( pathSuffix, http.Response(jsonEncode(body), statusCode, headers: { 'content-type': 'application/json', }), ); } @override Future send(http.BaseRequest request) async { requests.add(request); final String body = await _readBody(request); capturedBodies.add(body); final String path = request.url.path; final String method = request.method.toUpperCase(); for (final MapEntry entry in _responses.entries) { final _MatchedResponse match = entry.value; if (match.method != method) continue; final String suffix = entry.key.startsWith('$method:') ? entry.key.substring(method.length + 1) : entry.key; if (path.endsWith(suffix) || request.url.toString().contains(suffix)) { return http.StreamedResponse( Stream>.value(utf8.encode(match.response.body)), match.response.statusCode, headers: match.response.headers, request: request, ); } } return http.StreamedResponse( Stream>.value(utf8.encode('{}')), 404, request: request, ); } Future _readBody(http.BaseRequest request) async { if (request is http.Request) { return request.body; } final List bytes = await request.finalize().toBytes(); return utf8.decode(bytes); } @override void close() {} } class _MatchedResponse { _MatchedResponse({required this.method, required this.response}); final String method; final http.Response response; }