forked from loafle/openapi-generator-original
[dart][dart-dio-next] Authentication fixes and improvements (#9975)
* [dart-dio-next] Update http mock test library * [dart-dio-next] Fix authentication problems * correctly map authentication by type and scheme * add new authentication interceptor for `bearer` scheme - this currently does the same as the OAuth interceptor * add tests for all authentication types except OAuth * use temporary test library branch until new fixes and features get merge there * Actually commit the fixed test library dependency * Update http mock library * Format :/
This commit is contained in:
@@ -157,6 +157,7 @@ public class DartDioNextClientCodegen extends AbstractDartCodegen {
|
||||
final String authFolder = srcFolder + File.separator + "auth";
|
||||
supportingFiles.add(new SupportingFile("auth/api_key_auth.mustache", authFolder, "api_key_auth.dart"));
|
||||
supportingFiles.add(new SupportingFile("auth/basic_auth.mustache", authFolder, "basic_auth.dart"));
|
||||
supportingFiles.add(new SupportingFile("auth/bearer_auth.mustache", authFolder, "bearer_auth.dart"));
|
||||
supportingFiles.add(new SupportingFile("auth/oauth.mustache", authFolder, "oauth.dart"));
|
||||
supportingFiles.add(new SupportingFile("auth/auth.mustache", authFolder, "auth.dart"));
|
||||
|
||||
|
||||
@@ -73,7 +73,8 @@ class {{classname}} {
|
||||
extra: <String, dynamic>{
|
||||
'secure': <Map<String, String>>[{{^hasAuthMethods}}],{{/hasAuthMethods}}{{#hasAuthMethods}}
|
||||
{{#authMethods}}{
|
||||
'type': '{{type}}',
|
||||
'type': '{{type}}',{{#scheme}}
|
||||
'scheme': '{{scheme}}',{{/scheme}}
|
||||
'name': '{{name}}',{{#isApiKey}}
|
||||
'keyName': '{{keyParamName}}',
|
||||
'where': '{{#isKeyInQuery}}query{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}}',{{/isApiKey}}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:built_value/serializer.dart';
|
||||
import 'package:{{pubName}}/src/serializers.dart';{{/useBuiltValue}}
|
||||
import 'package:{{pubName}}/src/auth/api_key_auth.dart';
|
||||
import 'package:{{pubName}}/src/auth/basic_auth.dart';
|
||||
import 'package:{{pubName}}/src/auth/bearer_auth.dart';
|
||||
import 'package:{{pubName}}/src/auth/oauth.dart';
|
||||
{{#apiInfo}}{{#apis}}import 'package:{{pubName}}/src/api/{{classFilename}}.dart';
|
||||
{{/apis}}{{/apiInfo}}
|
||||
@@ -31,6 +32,7 @@ class {{clientName}} {
|
||||
this.dio.interceptors.addAll([
|
||||
OAuthInterceptor(),
|
||||
BasicAuthInterceptor(),
|
||||
BearerAuthInterceptor(),
|
||||
ApiKeyAuthInterceptor(),
|
||||
]);
|
||||
} else {
|
||||
@@ -44,6 +46,12 @@ class {{clientName}} {
|
||||
}
|
||||
}
|
||||
|
||||
void setBearerAuth(String name, String token) {
|
||||
if (this.dio.interceptors.any((i) => i is BearerAuthInterceptor)) {
|
||||
(this.dio.interceptors.firstWhere((i) => i is BearerAuthInterceptor) as BearerAuthInterceptor).tokens[name] = token;
|
||||
}
|
||||
}
|
||||
|
||||
void setBasicAuth(String name, String username, String password) {
|
||||
if (this.dio.interceptors.any((i) => i is BasicAuthInterceptor)) {
|
||||
(this.dio.interceptors.firstWhere((i) => i is BasicAuthInterceptor) as BasicAuthInterceptor).authInfo[name] = BasicAuthInfo(username, password);
|
||||
|
||||
@@ -8,7 +8,7 @@ class ApiKeyAuthInterceptor extends AuthInterceptor {
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
final authInfo = getAuthInfo(options, 'apiKey');
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'apiKey');
|
||||
for (final info in authInfo) {
|
||||
final authName = info['name'] as String;
|
||||
final authKeyName = info['keyName'] as String;
|
||||
|
||||
@@ -5,16 +5,10 @@ abstract class AuthInterceptor extends Interceptor {
|
||||
/// Get auth information on given route for the given type.
|
||||
/// Can return an empty list if type is not present on auth data or
|
||||
/// if route doesn't need authentication.
|
||||
List<Map<String, dynamic>> getAuthInfo(RequestOptions route, String type) {
|
||||
List<Map<String, String>> getAuthInfo(RequestOptions route, bool Function(Map<String, String> secure) handles) {
|
||||
if (route.extra.containsKey('secure')) {
|
||||
final auth = route.extra['secure'] as List<Map<String, String>>;
|
||||
final results = <Map<String, dynamic>>[];
|
||||
for (final info in auth) {
|
||||
if (info['type'] == type) {
|
||||
results.add(info);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return auth.where((secure) => handles(secure)).toList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class BasicAuthInterceptor extends AuthInterceptor {
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final metadataAuthInfo = getAuthInfo(options, 'basic');
|
||||
final metadataAuthInfo = getAuthInfo(options, (secure) => (secure['type'] == 'http' && secure['scheme'] == 'basic') || secure['type'] == 'basic');
|
||||
for (final info in metadataAuthInfo) {
|
||||
final authName = info['name'] as String;
|
||||
final basicAuthInfo = authInfo[authName];
|
||||
|
||||
23
modules/openapi-generator/src/main/resources/dart/libraries/dio/auth/bearer_auth.mustache
vendored
Normal file
23
modules/openapi-generator/src/main/resources/dart/libraries/dio/auth/bearer_auth.mustache
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{{>header}}
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:{{pubName}}/src/auth/auth.dart';
|
||||
|
||||
class BearerAuthInterceptor extends AuthInterceptor {
|
||||
final Map<String, String> tokens = {};
|
||||
|
||||
@override
|
||||
void onRequest(
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'http' && secure['scheme'] == 'bearer');
|
||||
for (final info in authInfo) {
|
||||
final token = tokens[info['name']];
|
||||
if (token != null) {
|
||||
options.headers['Authorization'] = 'Bearer ${token}';
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onRequest(options, handler);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class OAuthInterceptor extends AuthInterceptor {
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final authInfo = getAuthInfo(options, 'oauth');
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'oauth' && secure['type'] == 'oauth2');
|
||||
for (final info in authInfo) {
|
||||
final token = tokens[info['name']];
|
||||
if (token != null) {
|
||||
|
||||
@@ -67,6 +67,7 @@ lib/src/api_util.dart
|
||||
lib/src/auth/api_key_auth.dart
|
||||
lib/src/auth/auth.dart
|
||||
lib/src/auth/basic_auth.dart
|
||||
lib/src/auth/bearer_auth.dart
|
||||
lib/src/auth/oauth.dart
|
||||
lib/src/date_serializer.dart
|
||||
lib/src/model/additional_properties_class.dart
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:built_value/serializer.dart';
|
||||
import 'package:openapi/src/serializers.dart';
|
||||
import 'package:openapi/src/auth/api_key_auth.dart';
|
||||
import 'package:openapi/src/auth/basic_auth.dart';
|
||||
import 'package:openapi/src/auth/bearer_auth.dart';
|
||||
import 'package:openapi/src/auth/oauth.dart';
|
||||
import 'package:openapi/src/api/another_fake_api.dart';
|
||||
import 'package:openapi/src/api/default_api.dart';
|
||||
@@ -38,6 +39,7 @@ class Openapi {
|
||||
this.dio.interceptors.addAll([
|
||||
OAuthInterceptor(),
|
||||
BasicAuthInterceptor(),
|
||||
BearerAuthInterceptor(),
|
||||
ApiKeyAuthInterceptor(),
|
||||
]);
|
||||
} else {
|
||||
@@ -51,6 +53,12 @@ class Openapi {
|
||||
}
|
||||
}
|
||||
|
||||
void setBearerAuth(String name, String token) {
|
||||
if (this.dio.interceptors.any((i) => i is BearerAuthInterceptor)) {
|
||||
(this.dio.interceptors.firstWhere((i) => i is BearerAuthInterceptor) as BearerAuthInterceptor).tokens[name] = token;
|
||||
}
|
||||
}
|
||||
|
||||
void setBasicAuth(String name, String username, String password) {
|
||||
if (this.dio.interceptors.any((i) => i is BasicAuthInterceptor)) {
|
||||
(this.dio.interceptors.firstWhere((i) => i is BasicAuthInterceptor) as BasicAuthInterceptor).authInfo[name] = BasicAuthInfo(username, password);
|
||||
|
||||
@@ -137,6 +137,7 @@ class FakeApi {
|
||||
'secure': <Map<String, String>>[
|
||||
{
|
||||
'type': 'http',
|
||||
'scheme': 'signature',
|
||||
'name': 'http_signature_test',
|
||||
},
|
||||
],
|
||||
@@ -988,6 +989,7 @@ class FakeApi {
|
||||
'secure': <Map<String, String>>[
|
||||
{
|
||||
'type': 'http',
|
||||
'scheme': 'basic',
|
||||
'name': 'http_basic_test',
|
||||
},
|
||||
],
|
||||
@@ -1178,6 +1180,7 @@ class FakeApi {
|
||||
'secure': <Map<String, String>>[
|
||||
{
|
||||
'type': 'http',
|
||||
'scheme': 'bearer',
|
||||
'name': 'bearer_test',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -11,7 +11,7 @@ class ApiKeyAuthInterceptor extends AuthInterceptor {
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
final authInfo = getAuthInfo(options, 'apiKey');
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'apiKey');
|
||||
for (final info in authInfo) {
|
||||
final authName = info['name'] as String;
|
||||
final authKeyName = info['keyName'] as String;
|
||||
|
||||
@@ -8,16 +8,10 @@ abstract class AuthInterceptor extends Interceptor {
|
||||
/// Get auth information on given route for the given type.
|
||||
/// Can return an empty list if type is not present on auth data or
|
||||
/// if route doesn't need authentication.
|
||||
List<Map<String, dynamic>> getAuthInfo(RequestOptions route, String type) {
|
||||
List<Map<String, String>> getAuthInfo(RequestOptions route, bool Function(Map<String, String> secure) handles) {
|
||||
if (route.extra.containsKey('secure')) {
|
||||
final auth = route.extra['secure'] as List<Map<String, String>>;
|
||||
final results = <Map<String, dynamic>>[];
|
||||
for (final info in auth) {
|
||||
if (info['type'] == type) {
|
||||
results.add(info);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return auth.where((secure) => handles(secure)).toList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class BasicAuthInterceptor extends AuthInterceptor {
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final metadataAuthInfo = getAuthInfo(options, 'basic');
|
||||
final metadataAuthInfo = getAuthInfo(options, (secure) => (secure['type'] == 'http' && secure['scheme'] == 'basic') || secure['type'] == 'basic');
|
||||
for (final info in metadataAuthInfo) {
|
||||
final authName = info['name'] as String;
|
||||
final basicAuthInfo = authInfo[authName];
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:openapi/src/auth/auth.dart';
|
||||
|
||||
class BearerAuthInterceptor extends AuthInterceptor {
|
||||
final Map<String, String> tokens = {};
|
||||
|
||||
@override
|
||||
void onRequest(
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'http' && secure['scheme'] == 'bearer');
|
||||
for (final info in authInfo) {
|
||||
final token = tokens[info['name']];
|
||||
if (token != null) {
|
||||
options.headers['Authorization'] = 'Bearer ${token}';
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onRequest(options, handler);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ class OAuthInterceptor extends AuthInterceptor {
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
final authInfo = getAuthInfo(options, 'oauth');
|
||||
final authInfo = getAuthInfo(options, (secure) => secure['type'] == 'oauth' && secure['type'] == 'oauth2');
|
||||
for (final info in authInfo) {
|
||||
final token = tokens[info['name']];
|
||||
if (token != null) {
|
||||
|
||||
@@ -49,14 +49,14 @@ packages:
|
||||
name: built_collection
|
||||
url: "https://pub.intern.sk"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
version: "5.0.0"
|
||||
built_value:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: built_value
|
||||
url: "https://pub.intern.sk"
|
||||
source: hosted
|
||||
version: "8.1.0"
|
||||
version: "8.0.6"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -154,7 +154,7 @@ packages:
|
||||
name: http_mock_adapter
|
||||
url: "https://pub.intern.sk"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
version: "0.3.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -217,7 +217,7 @@ packages:
|
||||
name: mockito
|
||||
url: "https://pub.intern.sk"
|
||||
source: hosted
|
||||
version: "5.0.8"
|
||||
version: "5.0.11"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -11,8 +11,8 @@ dev_dependencies:
|
||||
built_collection: 5.0.0
|
||||
built_value: 8.0.6
|
||||
dio: 4.0.0
|
||||
http_mock_adapter: 0.2.1
|
||||
mockito: 5.0.8
|
||||
http_mock_adapter: 0.3.2
|
||||
mockito: 5.0.11
|
||||
openapi:
|
||||
path: ../petstore_client_lib_fake
|
||||
test: 1.17.4
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:http_mock_adapter/http_mock_adapter.dart';
|
||||
import 'package:openapi/openapi.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
Openapi client;
|
||||
DioAdapter tester;
|
||||
|
||||
setUp(() {
|
||||
client = Openapi(dio: Dio());
|
||||
tester = DioAdapter(dio: client.dio);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
tester.close();
|
||||
});
|
||||
|
||||
group('Authentication', () {
|
||||
test('http_basic', () async {
|
||||
client.setBasicAuth('http_basic_test', 'foo', 'bar');
|
||||
|
||||
tester.onPost(
|
||||
'/fake',
|
||||
(server) => server.reply(200, null),
|
||||
data: {
|
||||
'number': '1',
|
||||
'double': '1.1',
|
||||
'pattern_without_delimiter': 'pattern',
|
||||
'byte': '1',
|
||||
},
|
||||
headers: <String, dynamic>{
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'content-length': Matchers.integer,
|
||||
'authorization': Matchers.string,
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.getFakeApi().testEndpointParameters(
|
||||
number: 1,
|
||||
double_: 1.1,
|
||||
patternWithoutDelimiter: 'pattern',
|
||||
byte: '1',
|
||||
);
|
||||
|
||||
expect(response.statusCode, 200);
|
||||
});
|
||||
|
||||
test('bearer', () async {
|
||||
client.setBearerAuth('bearer_test', 'foobar');
|
||||
|
||||
tester.onDelete(
|
||||
'/fake',
|
||||
(server) => server.reply(200, null),
|
||||
headers: <String, dynamic>{
|
||||
'required_boolean_group': 'false',
|
||||
'authorization': Matchers.pattern('Bearer foobar'),
|
||||
},
|
||||
queryParameters: <String, dynamic>{
|
||||
'required_string_group': 1,
|
||||
'required_int64_group': 2,
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.getFakeApi().testGroupParameters(
|
||||
requiredStringGroup: 1,
|
||||
requiredBooleanGroup: false,
|
||||
requiredInt64Group: 2,
|
||||
);
|
||||
|
||||
expect(response.statusCode, 200);
|
||||
});
|
||||
|
||||
test('api_key', () async {
|
||||
client.setApiKey('api_key', 'SECRET_API_KEY');
|
||||
|
||||
tester.onGet(
|
||||
'/store/inventory',
|
||||
(server) => server.reply(200, {
|
||||
'foo': 999,
|
||||
}),
|
||||
headers: <String, dynamic>{
|
||||
'api_key': 'SECRET_API_KEY',
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.getStoreApi().getInventory();
|
||||
|
||||
expect(response.statusCode, 200);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -7,27 +7,25 @@ import 'package:http_mock_adapter/http_mock_adapter.dart';
|
||||
import 'package:openapi/openapi.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../matcher/list_param_matcher.dart';
|
||||
|
||||
void main() {
|
||||
Openapi client;
|
||||
DioAdapter server;
|
||||
DioAdapter tester;
|
||||
|
||||
setUp(() {
|
||||
server = DioAdapter();
|
||||
client = Openapi(dio: Dio()..httpClientAdapter = server);
|
||||
client = Openapi(dio: Dio());
|
||||
tester = DioAdapter(dio: client.dio);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
server.close();
|
||||
tester.close();
|
||||
});
|
||||
|
||||
group(FakeApi, () {
|
||||
group('testEndpointParameters', () {
|
||||
test('complete', () async {
|
||||
server.onPost(
|
||||
tester.onPost(
|
||||
'/fake',
|
||||
(request) => request.reply(200, null),
|
||||
(server) => server.reply(200, null),
|
||||
data: {
|
||||
'number': '3',
|
||||
'double': '-13.57',
|
||||
@@ -65,9 +63,9 @@ void main() {
|
||||
});
|
||||
|
||||
test('minimal', () async {
|
||||
server.onPost(
|
||||
tester.onPost(
|
||||
'/fake',
|
||||
(request) => request.reply(200, null),
|
||||
(server) => server.reply(200, null),
|
||||
data: {
|
||||
'byte': '0',
|
||||
'double': '-13.57',
|
||||
@@ -95,21 +93,21 @@ void main() {
|
||||
test('in body data', () async {
|
||||
// Not sure if this is correct, we are not sending
|
||||
// form data in the body but some weird map
|
||||
server.onGet(
|
||||
tester.onGet(
|
||||
'/fake',
|
||||
(request) => request.reply(200, null),
|
||||
(server) => server.reply(200, null),
|
||||
data: {
|
||||
'enum_form_string': 'formString',
|
||||
'enum_form_string_array': ListParamMatcher(
|
||||
expected: ListParam(
|
||||
'enum_form_string_array': Matchers.listParam<String>(
|
||||
ListParam(
|
||||
['foo', 'bar'],
|
||||
ListFormat.csv,
|
||||
),
|
||||
),
|
||||
},
|
||||
queryParameters: <String, dynamic>{
|
||||
'enum_query_string_array': ListParamMatcher(
|
||||
expected: ListParam(
|
||||
'enum_query_string_array': Matchers.listParam<String>(
|
||||
ListParam(
|
||||
['a', 'b', 'c'],
|
||||
ListFormat.multi,
|
||||
),
|
||||
|
||||
@@ -6,31 +6,28 @@ import 'package:http_parser/http_parser.dart';
|
||||
import 'package:openapi/openapi.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../matcher/form_data_matcher.dart';
|
||||
import '../matcher/list_param_matcher.dart';
|
||||
|
||||
void main() {
|
||||
const photo1 = 'https://localhost/photo1.jpg';
|
||||
const photo2 = 'https://localhost/photo2.jpg';
|
||||
|
||||
Openapi client;
|
||||
DioAdapter server;
|
||||
DioAdapter tester;
|
||||
|
||||
setUp(() {
|
||||
server = DioAdapter();
|
||||
client = Openapi(dio: Dio()..httpClientAdapter = server);
|
||||
client = Openapi(dio: Dio());
|
||||
tester = DioAdapter(dio: client.dio);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
server.close();
|
||||
tester.close();
|
||||
});
|
||||
|
||||
group(PetApi, () {
|
||||
group('getPetById', () {
|
||||
test('complete', () async {
|
||||
server.onGet(
|
||||
tester.onGet(
|
||||
'/pet/5',
|
||||
(request) => request.reply(200, {
|
||||
(server) => server.reply(200, {
|
||||
'id': 5,
|
||||
'name': 'Paula',
|
||||
'status': 'sold',
|
||||
@@ -53,9 +50,6 @@ void main() {
|
||||
},
|
||||
]
|
||||
}),
|
||||
headers: {
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.getPetApi().getPetById(petId: 5);
|
||||
@@ -72,16 +66,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('minimal', () async {
|
||||
server.onGet(
|
||||
tester.onGet(
|
||||
'/pet/5',
|
||||
(request) => request.reply(200, {
|
||||
(server) => server.reply(200, {
|
||||
'id': 5,
|
||||
'name': 'Paula',
|
||||
'photoUrls': <String>[],
|
||||
}),
|
||||
headers: {
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
},
|
||||
);
|
||||
|
||||
final response = await client.getPetApi().getPetById(petId: 5);
|
||||
@@ -99,9 +90,9 @@ void main() {
|
||||
|
||||
group('addPet', () {
|
||||
test('complete', () async {
|
||||
server.onPost(
|
||||
tester.onPost(
|
||||
'/pet',
|
||||
(request) => request.reply(200, ''),
|
||||
(server) => server.reply(200, ''),
|
||||
data: {
|
||||
'id': 5,
|
||||
'name': 'Paula',
|
||||
@@ -125,7 +116,7 @@ void main() {
|
||||
},
|
||||
]
|
||||
},
|
||||
headers: {
|
||||
headers: <String, dynamic>{
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
Headers.contentLengthHeader: Matchers.integer,
|
||||
},
|
||||
@@ -153,15 +144,15 @@ void main() {
|
||||
});
|
||||
|
||||
test('minimal', () async {
|
||||
server.onPost(
|
||||
tester.onPost(
|
||||
'/pet',
|
||||
(request) => request.reply(200, ''),
|
||||
(server) => server.reply(200, ''),
|
||||
data: {
|
||||
'id': 5,
|
||||
'name': 'Paula',
|
||||
'photoUrls': <String>[],
|
||||
},
|
||||
headers: {
|
||||
headers: <String, dynamic>{
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
Headers.contentLengthHeader: Matchers.integer,
|
||||
},
|
||||
@@ -178,9 +169,9 @@ void main() {
|
||||
|
||||
group('getMultiplePets', () {
|
||||
test('findByStatus', () async {
|
||||
server.onRoute(
|
||||
tester.onRoute(
|
||||
'/pet/findByStatus',
|
||||
(request) => request.reply(200, [
|
||||
(server) => server.reply(200, [
|
||||
{
|
||||
'id': 5,
|
||||
'name': 'Paula',
|
||||
@@ -197,16 +188,13 @@ void main() {
|
||||
request: Request(
|
||||
method: RequestMethods.get,
|
||||
queryParameters: <String, dynamic>{
|
||||
'status': ListParamMatcher<dynamic>(
|
||||
expected: ListParam<String>(
|
||||
'status': Matchers.listParam<String>(
|
||||
ListParam(
|
||||
['available', 'sold'],
|
||||
ListFormat.csv,
|
||||
),
|
||||
),
|
||||
},
|
||||
headers: <String, dynamic>{
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -237,9 +225,9 @@ void main() {
|
||||
contentType: MediaType.parse('image/png'),
|
||||
);
|
||||
|
||||
server.onRoute(
|
||||
tester.onRoute(
|
||||
'/fake/5/uploadImageWithRequiredFile',
|
||||
(request) => request.reply(200, {
|
||||
(server) => server.reply(200, {
|
||||
'code': 200,
|
||||
'type': 'success',
|
||||
'message': 'File uploaded',
|
||||
@@ -251,8 +239,8 @@ void main() {
|
||||
Matchers.pattern('multipart/form-data'),
|
||||
Headers.contentLengthHeader: Matchers.integer,
|
||||
},
|
||||
data: FormDataMatcher(
|
||||
expected: FormData.fromMap(<String, dynamic>{
|
||||
data: Matchers.formData(
|
||||
FormData.fromMap(<String, dynamic>{
|
||||
r'requiredFile': file,
|
||||
}),
|
||||
),
|
||||
@@ -274,9 +262,9 @@ void main() {
|
||||
contentType: MediaType.parse('image/png'),
|
||||
);
|
||||
|
||||
server.onRoute(
|
||||
tester.onRoute(
|
||||
'/fake/3/uploadImageWithRequiredFile',
|
||||
(request) => request.reply(200, {
|
||||
(server) => server.reply(200, {
|
||||
'code': 200,
|
||||
'type': 'success',
|
||||
'message': 'File uploaded',
|
||||
@@ -288,8 +276,8 @@ void main() {
|
||||
Matchers.pattern('multipart/form-data'),
|
||||
Headers.contentLengthHeader: Matchers.integer,
|
||||
},
|
||||
data: FormDataMatcher(
|
||||
expected: FormData.fromMap(<String, dynamic>{
|
||||
data: Matchers.formData(
|
||||
FormData.fromMap(<String, dynamic>{
|
||||
'additionalMetadata': 'foo',
|
||||
r'requiredFile': file,
|
||||
}),
|
||||
|
||||
@@ -5,41 +5,33 @@ import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
Openapi client;
|
||||
DioAdapter server;
|
||||
DioAdapter tester;
|
||||
|
||||
setUp(() {
|
||||
server = DioAdapter();
|
||||
client = Openapi(dio: Dio()..httpClientAdapter = server);
|
||||
client = Openapi(dio: Dio());
|
||||
tester = DioAdapter(dio: client.dio);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
server.close();
|
||||
tester.close();
|
||||
});
|
||||
|
||||
group(StoreApi, () {
|
||||
group('getInventory', () {
|
||||
test('with API key', () async {
|
||||
client.setApiKey('api_key', 'SECRET_API_KEY');
|
||||
test('getInventory', () async {
|
||||
tester.onGet(
|
||||
'/store/inventory',
|
||||
(server) => server.reply(200, {
|
||||
'foo': 5,
|
||||
'bar': 999,
|
||||
'baz': 0,
|
||||
}),
|
||||
);
|
||||
|
||||
server.onGet(
|
||||
'/store/inventory',
|
||||
(request) => request.reply(200, {
|
||||
'foo': 5,
|
||||
'bar': 999,
|
||||
'baz': 0,
|
||||
}),
|
||||
headers: <String, dynamic>{
|
||||
Headers.contentTypeHeader: Matchers.pattern('application/json'),
|
||||
'api_key': 'SECRET_API_KEY',
|
||||
},
|
||||
);
|
||||
final response = await client.getStoreApi().getInventory();
|
||||
|
||||
final response = await client.getStoreApi().getInventory();
|
||||
|
||||
expect(response.statusCode, 200);
|
||||
expect(response.data, isNotNull);
|
||||
expect(response.data.length, 3);
|
||||
});
|
||||
expect(response.statusCode, 200);
|
||||
expect(response.data, isNotNull);
|
||||
expect(response.data.length, 3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http_mock_adapter/src/matchers/matcher.dart';
|
||||
|
||||
class FormDataMatcher extends Matcher {
|
||||
final FormData expected;
|
||||
|
||||
const FormDataMatcher({@required this.expected});
|
||||
|
||||
@override
|
||||
bool matches(dynamic actual) {
|
||||
if (actual is! FormData) {
|
||||
return false;
|
||||
}
|
||||
final data = actual as FormData;
|
||||
return MapEquality<String, String>().equals(
|
||||
Map.fromEntries(expected.fields),
|
||||
Map.fromEntries(data.fields),
|
||||
) &&
|
||||
MapEquality<String, MultipartFile>().equals(
|
||||
Map.fromEntries(expected.files),
|
||||
Map.fromEntries(data.files),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import 'package:dio/src/parameter.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http_mock_adapter/src/matchers/matcher.dart';
|
||||
|
||||
class ListParamMatcher<T> extends Matcher {
|
||||
final ListParam<T> expected;
|
||||
|
||||
const ListParamMatcher({@required this.expected});
|
||||
|
||||
@override
|
||||
bool matches(dynamic actual) {
|
||||
return actual is ListParam<T> &&
|
||||
ListEquality<T>().equals(
|
||||
actual.value,
|
||||
expected.value,
|
||||
) &&
|
||||
actual.format == expected.format;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user