EMASCurlTests/EMASCurlSimpleTest.m (260 lines of code) (raw):
//
// EMASCurlSimpleTest.m
// EMASCurlTests
//
// Created by xuyecan on 2024/12/16.
//
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import <EMASCurl/EMASCurl.h>
#import "EMASCurlTestConstants.h"
static NSURLSession *session;
@interface EMASCurlSimpleTestBase : XCTestCase
@end
@implementation EMASCurlSimpleTestBase
#pragma mark - Helper Methods
- (void)executeRequest:(NSString *)endpoint
path:(NSString *)path
method:(NSString *)method
body:(NSDictionary *)body
headers:(NSDictionary *)headers
validationBlock:(void (^)(NSData *data, NSHTTPURLResponse *response))validationBlock {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", endpoint, path]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
// Add body if provided
if (body) {
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&jsonError];
XCTAssertNil(jsonError, @"Failed to serialize request body: %@", jsonError);
request.HTTPBody = bodyData;
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
}
// Add custom headers
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
[request setValue:value forHTTPHeaderField:key];
}];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
XCTAssertNil(error, @"Request failed with error: %@", error);
XCTAssertNotNil(response, @"No response received");
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
// Common response validation
[self validateCommonResponse:httpResponse];
// Custom validation if provided
if (validationBlock) {
validationBlock(data, httpResponse);
}
dispatch_semaphore_signal(semaphore);
}];
[task resume];
XCTAssertEqual(dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)), 0, @"Request timed out");
}
- (void)validateCommonResponse:(NSHTTPURLResponse *)response {
XCTAssertEqual(response.statusCode, 200, @"Expected status code 200, got %ld", (long)response.statusCode);
}
- (void)validateEchoResponse:(NSData *)data expectedMethod:(NSString *)method {
NSError *jsonError;
NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
XCTAssertNil(jsonError, @"Failed to parse response JSON: %@", jsonError);
XCTAssertEqualObjects(responseData[@"method"], method, @"Expected %@ method in response", method);
}
#pragma mark - Test Methods
- (void)headRequest:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_ECHO
method:@"HEAD"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
XCTAssertEqual(data.length, 0, @"HEAD request should not return body data");
}];
}
- (void)deleteRequest:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_ECHO
method:@"DELETE"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"DELETE"];
}];
}
- (void)putRequest:(NSString *)endpoint {
NSDictionary *requestBody = @{@"test": @"data"};
[self executeRequest:endpoint
path:PATH_ECHO
method:@"PUT"
body:requestBody
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"PUT"];
NSError *jsonError;
NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
XCTAssertNil(jsonError);
NSString *bodyContent = responseData[@"body"];
XCTAssertNotNil(bodyContent, @"Expected body content in response");
XCTAssertTrue([bodyContent containsString:@"test"], @"Expected request body to be echoed back");
}];
}
- (void)postRequest:(NSString *)endpoint {
NSDictionary *requestBody = @{
@"name": @"test_user",
@"age": @25,
@"email": @"test@example.com"
};
[self executeRequest:endpoint
path:PATH_ECHO
method:@"POST"
body:requestBody
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"POST"];
NSError *jsonError;
NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
XCTAssertNil(jsonError);
NSString *bodyContent = responseData[@"body"];
XCTAssertNotNil(bodyContent, @"Expected body content in response");
XCTAssertTrue([bodyContent containsString:@"test_user"], @"Expected name in echoed body");
XCTAssertTrue([bodyContent containsString:@"test@example.com"], @"Expected email in echoed body");
}];
}
- (void)optionsRequest:(NSString *)endpoint {
NSDictionary *headers = @{
@"Access-Control-Request-Headers": @"*",
@"Access-Control-Request-Method": @"PUT, DELETE",
@"Origin": @"example.com"
};
[self executeRequest:endpoint
path:PATH_ECHO
method:@"OPTIONS"
body:nil
headers:headers
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"OPTIONS"];
NSDictionary *responseHeaders = response.allHeaderFields;
XCTAssertNotNil(responseHeaders[@"access-control-allow-origin"], @"Expected CORS headers in response");
XCTAssertNotNil(responseHeaders[@"access-control-allow-methods"], @"Expected allowed methods in response");
}];
}
- (void)getRequest:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_ECHO
method:@"GET"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"GET"];
}];
}
- (void)getRedirectRequest:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_REDIRECT
method:@"GET"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"GET"];
}];
}
- (void)getRedirectChainRequest:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_REDIRECT_CHAIN
method:@"GET"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
[self validateEchoResponse:data expectedMethod:@"GET"];
}];
}
- (void)getGzipResponse:(NSString *)endpoint {
[self executeRequest:endpoint
path:PATH_GZIP_RESPONSE
method:@"GET"
body:nil
headers:nil
validationBlock:^(NSData *data, NSHTTPURLResponse *response) {
NSDictionary *responseHeaders = response.allHeaderFields;
XCTAssertEqualObjects(responseHeaders[@"content-encoding"], @"gzip", @"Expected gzip content encoding");
XCTAssertEqualObjects(responseHeaders[@"content-type"], @"application/json", @"Expected JSON content type");
NSError *jsonError;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
XCTAssertNil(jsonError, @"Failed to parse JSON response: %@", jsonError);
XCTAssertEqualObjects(jsonResponse[@"message"], @"This is a gzipped response", @"Unexpected response message");
}];
}
@end
@interface EMASCurlSimpleTestHttp11 : EMASCurlSimpleTestBase
@end
@implementation EMASCurlSimpleTestHttp11
+ (void)setUp {
[EMASCurlProtocol setDebugLogEnabled:YES];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPShouldUsePipelining = YES; // Enable redirect following
config.HTTPShouldSetCookies = YES;
[EMASCurlProtocol installIntoSessionConfiguration:config];
session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
}
- (void)testHeadRequest {
[self headRequest:HTTP11_ENDPOINT];
}
- (void)testDeleteRequest {
[self deleteRequest:HTTP11_ENDPOINT];
}
- (void)testPutRequest {
[self putRequest:HTTP11_ENDPOINT];
}
- (void)testPostRequest {
[self postRequest:HTTP11_ENDPOINT];
}
- (void)testOptionsRequest {
[self optionsRequest:HTTP11_ENDPOINT];
}
- (void)testGetRequest {
[self getRequest:HTTP11_ENDPOINT];
}
- (void)testGetRedirectRequest {
[self getRedirectRequest:HTTP11_ENDPOINT];
}
- (void)testGetRedirectChainRequest {
[self getRedirectChainRequest:HTTP11_ENDPOINT];
}
- (void)testGetGzipResponse {
[self getGzipResponse:HTTP11_ENDPOINT];
}
@end
@interface EMASCurlSimpleTestHttp2 : EMASCurlSimpleTestBase
@end
@implementation EMASCurlSimpleTestHttp2
+ (void)setUp {
[EMASCurlProtocol setDebugLogEnabled:YES];
[EMASCurlProtocol setHTTPVersion:HTTP2];
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
NSString *certPath = [testBundle pathForResource:@"ca" ofType:@"crt"];
XCTAssertNotNil(certPath, @"Certificate file not found in test bundle.");
[EMASCurlProtocol setSelfSignedCAFilePath:certPath];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPShouldUsePipelining = YES; // Enable redirect following
config.HTTPShouldSetCookies = YES;
[EMASCurlProtocol installIntoSessionConfiguration:config];
session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
}
- (void)testHeadRequest {
[self headRequest:HTTP2_ENDPOINT];
}
- (void)testDeleteRequest {
[self deleteRequest:HTTP2_ENDPOINT];
}
- (void)testPutRequest {
[self putRequest:HTTP2_ENDPOINT];
}
- (void)testPostRequest {
[self postRequest:HTTP2_ENDPOINT];
}
- (void)testOptionsRequest {
[self optionsRequest:HTTP2_ENDPOINT];
}
- (void)testGetRequest {
[self getRequest:HTTP2_ENDPOINT];
}
- (void)testGetRedirectRequest {
[self getRedirectRequest:HTTP2_ENDPOINT];
}
- (void)testGetRedirectChainRequest {
[self getRedirectChainRequest:HTTP2_ENDPOINT];
}
- (void)testGetGzipResponse {
[self getGzipResponse:HTTP2_ENDPOINT];
}
@end