blob: 620510741f32d9a857cfc54811488dbadf3cc1f9 [file] [log] [blame]
/*
* Copyright (c) 2011-2012 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
#include <bsdtests.h>
#if DISPATCH_API_VERSION >= 20111008 && !TARGET_OS_EMBEDDED
#include <Security/Security.h>
#include <dispatch/dispatch.h>
#include <dispatch/private.h>
#include <fcntl.h>
#define printf_data(p, s) ({ \
__typeof__(s) _i; \
for (_i=0; _i<s; _i++) { \
printf("%c", ((uint8_t *)p)[_i]); \
} \
printf("\n"); \
})
#define test_data_equal(a, b, c) ({ \
const void * ptr, * ptr2; \
size_t size, size2; \
dispatch_data_t map = dispatch_data_create_map(b, &ptr, &size); \
assert(map); \
dispatch_data_t map2 = dispatch_data_create_map(c, &ptr2, &size2); \
assert(map); \
test_long(a ": length", size, size2); \
test_long(a ": memcmp", memcmp(ptr, ptr2, size), 0); \
if (size != size2 || (memcmp(ptr, ptr2, size) != 0)) { \
printf_data(ptr, size); \
printf_data(ptr2, size2); \
} \
dispatch_release(map); \
dispatch_release(map2); \
})
static bool
dispatch_data_equal(dispatch_data_t a, dispatch_data_t b)
{
const void * ptr, * ptr2;
size_t size, size2;
bool equal = true;
dispatch_data_t map = dispatch_data_create_map(a, &ptr, &size); \
assert(map);
dispatch_data_t map2 = dispatch_data_create_map(b, &ptr2, &size2); \
assert(map2);
if (size == size2) {
if (memcmp(ptr, ptr2, size) != 0) {
equal = false;
}
} else {
equal = false;
}
dispatch_release(map);
dispatch_release(map2);
return equal;
}
static dispatch_data_t
execute_sectransform(SecTransformRef transformRef, dispatch_data_t data)
{
const void * bytes;
size_t size;
dispatch_data_t map = dispatch_data_create_map(data, &bytes, &size);
assert(map);
CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, bytes, size);
assert(dataRef);
dispatch_release(map);
SecTransformSetAttribute(transformRef, kSecTransformInputAttributeName, dataRef, NULL);
CFDataRef transformedDataRef = SecTransformExecute(transformRef, NULL);
assert(transformedDataRef);
CFRelease(dataRef);
dispatch_data_t output = dispatch_data_create(CFDataGetBytePtr(transformedDataRef), CFDataGetLength(transformedDataRef), dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_DEFAULT);
CFRelease(transformedDataRef);
return output;
}
#pragma mark - UTF tests
static uint8_t utf8[] = {
0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66, 0x6f,
0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xeb, 0x84, 0x88, 0xeb, 0xac,
0xb4, 0x20, 0xec, 0x98, 0xa4, 0xeb, 0x9e, 0x98, 0x20, 0xea, 0xb7, 0xb8, 0xeb, 0xa6, 0xac, 0xea, 0xb3, 0xa0, 0x20, 0xea, 0xb7,
0xb8, 0x20, 0xeb, 0x8f, 0x99, 0xec, 0x95, 0x88, 0x20, 0xeb, 0xa7, 0x9b, 0xec, 0x9e, 0x88, 0xeb, 0x8a, 0x94, 0x20, 0xec, 0x83,
0x9d, 0xec, 0x84, 0xa0, 0xec, 0x9d, 0x80, 0x20, 0xea, 0xb3, 0xa0, 0xeb, 0xa7, 0x88, 0xec, 0x9b, 0xa0, 0xec, 0x96, 0xb4, 0x2e,
0x20, 0xf0, 0x9f, 0x98, 0x84, 0xf0, 0x9f, 0x98, 0x8a, 0xf0, 0x9f, 0x98, 0x83, 0xe2, 0x98, 0xba, 0xf0, 0x9f, 0x98, 0x89, 0xf0,
0x9f, 0x98, 0x8d, 0xf0, 0x9f, 0x92, 0xa8, 0xf0, 0x9f, 0x92, 0xa9, 0xf0, 0x9f, 0x91, 0x8e, 0x2e,
};
static uint16_t utf16[] = {
0xfeff, 0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xb108, 0xbb34, 0x20,
0xc624, 0xb798, 0x20, 0xadf8, 0xb9ac, 0xace0, 0x20, 0xadf8, 0x20, 0xb3d9, 0xc548, 0x20, 0xb9db, 0xc788, 0xb294, 0x20, 0xc0dd,
0xc120, 0xc740, 0x20, 0xace0, 0xb9c8, 0xc6e0, 0xc5b4, 0x2e, 0x20, 0xd83d, 0xde04, 0xd83d, 0xde0a, 0xd83d, 0xde03, 0x263a, 0xd83d,
0xde09, 0xd83d, 0xde0d, 0xd83d, 0xdca8, 0xd83d, 0xdca9, 0xd83d, 0xdc4e, 0x2e,
};
static uint16_t utf16be[] = {
0xfffe, 0x5300, 0x6f00, 0x2000, 0x6c00, 0x6f00, 0x6e00, 0x6700, 0x2000, 0x6100, 0x6e00, 0x6400, 0x2000, 0x7400, 0x6800, 0x6100,
0x6e00, 0x6b00, 0x7300, 0x2000, 0x6600, 0x6f00, 0x7200, 0x2000, 0x6100, 0x6c00, 0x6c00, 0x2000, 0x7400, 0x6800, 0x6500, 0x2000,
0x6600, 0x6900, 0x7300, 0x6800, 0x2e00, 0x2000, 0x8b1, 0x34bb, 0x2000, 0x24c6, 0x98b7, 0x2000, 0xf8ad, 0xacb9, 0xe0ac, 0x2000,
0xf8ad, 0x2000, 0xd9b3, 0x48c5, 0x2000, 0xdbb9, 0x88c7, 0x94b2, 0x2000, 0xddc0, 0x20c1, 0x40c7, 0x2000, 0xe0ac, 0xc8b9, 0xe0c6,
0xb4c5, 0x2e00, 0x2000, 0x3dd8, 0x4de, 0x3dd8, 0xade, 0x3dd8, 0x3de, 0x3a26, 0x3dd8, 0x9de, 0x3dd8, 0xdde, 0x3dd8, 0xa8dc,
0x3dd8, 0xa9dc, 0x3dd8, 0x4edc, 0x2e00,
};
// Invalid due to half missing surrogate
static uint16_t utf16le_invalid[] = {
0xfeff, 0x53, 0x6f, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x6b, 0x73, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2e, 0x20, 0xb108, 0xbb34, 0x20,
0xc624, 0xb798, 0x20, 0xadf8, 0xb9ac, 0xace0, 0x20, 0xadf8, 0x20, 0xb3d9, 0xc548, 0x20, 0xb9db, 0xc788, 0xb294, 0x20, 0xc0dd,
0xc120, 0xc740, 0x20, 0xace0, 0xb9c8, 0xc6e0, 0xc5b4, 0x2e, 0x20, 0xd83d, 0xde04, 0xd83d, 0xde0a, 0xd83d, 0xde03, 0x263a, 0xd83d,
0xde09, 0xd83d, 0xde0d, 0xd83d, 0xdca8, 0xd83d, 0xd83d, 0xdc4e, 0x2e,
};
void
invalid_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8 + sizeof(utf8) - 8, 8, NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
test_ptr_null("dispatch_data_create_with_transform (UTF8 (invalid start) -> UTF16LE)", transformed);
dispatch_release(utf8_data);
(void)context;
}
void
truncated_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8) - 3, NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
test_ptr_null("dispatch_data_create_with_transform (UTF8 (truncated) -> UTF16LE)", transformed);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf8_test);
}
void
invalid_utf16le_surrogate_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16le_invalid, sizeof(utf16le_invalid), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_null("dispatch_data_create_with_transform (UTF16LE (missing surrogate) -> UTF8)", transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, truncated_utf8_test);
}
void
invalid_utf16le_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16, (sizeof(utf16) % 2) + 1, NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_null("dispatch_data_create_with_transform (UTF16LE (invalid) -> UTF8)", transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf16le_surrogate_test);
}
void
utf16le_bytes_to_utf8_test(void * context)
{
dispatch_data_t utf16_data = dispatch_data_empty;
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
size_t i;
for (i=0; i<sizeof(utf16); i++) {
dispatch_data_t new = dispatch_data_create((char*)utf16 + i, 1, NULL, ^{});
dispatch_data_t concat = dispatch_data_create_concat(utf16_data, new);
dispatch_release(new);
dispatch_release(utf16_data);
utf16_data = concat;
}
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE (any, single bytes) -> UTF8)", transformed);
test_data_equal("utf16le_bytes_to_utf8_test", transformed, utf8_data);
dispatch_release(transformed);
dispatch_release(utf8_data);
dispatch_release(utf16_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, invalid_utf16le_test);
}
void
utf8_bytes_to_utf16le_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_empty;
dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
size_t i;
for (i=0; i<sizeof(utf8); i++) {
dispatch_data_t new = dispatch_data_create(utf8 + i, 1, NULL, ^{});
dispatch_data_t concat = dispatch_data_create_concat(utf8_data, new);
dispatch_release(new);
dispatch_release(utf8_data);
utf8_data = concat;
}
dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
test_ptr_notnull("dispatch_data_create_with_transform (UTF8 (any, single bytes) -> UTF16LE)", transformed);
test_data_equal("utf8_bytes_to_utf16le_test", transformed, utf16_data);
dispatch_release(transformed);
dispatch_release(utf8_data);
dispatch_release(utf16_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_bytes_to_utf8_test);
}
void
utf16be_detect_to_utf16le_test(void * context)
{
dispatch_data_t utf16be_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16be_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE (any) -> UTF16LE)", transformed);
test_data_equal("utf16be_detect_to_utf16le_test", transformed, utf16_data);
dispatch_release(transformed);
dispatch_release(utf16be_data);
dispatch_release(utf16_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_bytes_to_utf16le_test);
}
void
utf16be_detect_to_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE (any) -> UTF8)", transformed);
test_data_equal("utf16be_detect_to_utf8_test", transformed, utf8_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_detect_to_utf16le_test);
}
void
utf16le_detect_to_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF_ANY, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE (any) -> UTF8)", transformed);
test_data_equal("utf16le_detect_to_utf8_test", transformed, utf8_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_detect_to_utf8_test);
}
void
utf16be_to_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16BE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16BE -> UTF8)", transformed);
test_data_equal("utf16be_to_utf8_test", transformed, utf8_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_detect_to_utf8_test);
}
void
utf16le_to_utf8_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf16_data, DISPATCH_DATA_FORMAT_TYPE_UTF16LE, DISPATCH_DATA_FORMAT_TYPE_UTF8);
test_ptr_notnull("dispatch_data_create_with_transform (UTF16LE -> UTF8)", transformed);
test_data_equal("utf16le_to_utf8_test", transformed, utf8_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16be_to_utf8_test);
}
void
utf8_to_utf16be_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16be, sizeof(utf16be), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16BE);
test_ptr_notnull("dispatch_data_create_with_transform (UTF8 -> UTF16BE)", transformed);
test_data_equal("utf8_to_utf16be_test", transformed, utf16_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf16le_to_utf8_test);
}
void
utf8_to_utf16le_test(void * context)
{
dispatch_data_t utf8_data = dispatch_data_create(utf8, sizeof(utf8), NULL, ^{});
dispatch_data_t utf16_data = dispatch_data_create(utf16, sizeof(utf16), NULL, ^{});
dispatch_data_t transformed = dispatch_data_create_with_transform(utf8_data, DISPATCH_DATA_FORMAT_TYPE_UTF8, DISPATCH_DATA_FORMAT_TYPE_UTF16LE);
test_ptr_notnull("dispatch_data_create_with_transform (UTF8 -> UTF16LE)", transformed);
test_data_equal("utf8_to_utf16le_test", transformed, utf16_data);
dispatch_release(transformed);
dispatch_release(utf16_data);
dispatch_release(utf8_data);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_to_utf16be_test);
}
#pragma mark - base32 tests
void
decode32_corrupt_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
void * corrupt_buffer = malloc(dispatch_data_get_size(sectransform_data));
const void * source;
size_t size;
dispatch_data_t map = dispatch_data_create_map(sectransform_data, &source, &size);
memcpy(corrupt_buffer, source, size);
size_t i;
for (i=0; i<size; i += (arc4random() % (int)(size * 0.05))) {
char x = arc4random() & 0xff;
while ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x >= '0' && x <= '9') || x == '/' || x == '+' || x == '=') {
x = arc4random() & 0xff;
}
((char*)corrupt_buffer)[i] = x;
}
dispatch_release(map);
dispatch_release(sectransform_data);
dispatch_data_t corrupt_data = dispatch_data_create(corrupt_buffer, size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
dispatch_data_t transform_data = dispatch_data_create_with_transform(corrupt_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_null("decode32_corrupt_test: dispatch_data_create_with_transform", transform_data);
dispatch_release(corrupt_data);
close(fd);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, utf8_to_utf16le_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
void
chunking_decode32_test(void * context)
{
(void)context;
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_data_t __block data = dispatch_data_empty;
int i;
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("read", 0);
for (i=0; i<4096; i++) {
dispatch_group_enter(group);
dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
assert(error == 0);
dispatch_data_t concat = dispatch_data_create_concat(data, d);
dispatch_release(data);
data = concat;
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(queue);
dispatch_release(group);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_notnull("chunking_decode32_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("chunking_decode32_test", transformed_data, data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
dispatch_release(data);
close(fd);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, decode32_corrupt_test);
}
void
chunking_encode32_test(void * context)
{
(void)context;
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_data_t __block data = dispatch_data_empty;
int i;
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("read", 0);
for (i=0; i<4096; i++) {
dispatch_group_enter(group);
dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
assert(error == 0);
dispatch_data_t concat = dispatch_data_create_concat(data, d);
dispatch_release(data);
data = concat;
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(queue);
dispatch_release(group);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE32);
test_ptr_notnull("chunking_encode32_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("chunking_encode32_test", transformed_data, sectransform_data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
dispatch_release(data);
close(fd);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, chunking_decode32_test);
}
void
decode32_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE32, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_notnull("decode32_test: dispatch_data_create_with_transform", transform_data);
test_data_equal("decode32_test", transform_data, data);
dispatch_release(sectransform_data);
dispatch_release(transform_data);
close(fd);
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, chunking_encode32_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
void
encode32_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase32Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE32);
test_ptr_notnull("encode32_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("encode32_test", transformed_data, sectransform_data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
close(fd);
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode32_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
#pragma mark - base64 tests
void
decode64_loop_test(void * context)
{
if (getenv("LOOP_SKIP") == NULL)
{
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
size_t i, __block tests = 0;
for (i=1; i<4097; i++) {
dispatch_read(fd, i, dispatch_get_global_queue(0, 0), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
if (dispatch_data_equal(transform_data, data)) {
tests++;
}
dispatch_release(sectransform_data);
dispatch_release(transform_data);
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
dispatch_release(sema);
close(fd);
test_long("decode64_loop_test", tests, 4096);
}
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, encode32_test);
}
void
decode64_corrupt_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
void * corrupt_buffer = malloc(dispatch_data_get_size(sectransform_data));
const void * source;
size_t size;
dispatch_data_t map = dispatch_data_create_map(sectransform_data, &source, &size);
memcpy(corrupt_buffer, source, size);
size_t i;
for (i=0; i<size; i += (arc4random() % (int)(size * 0.05))) {
char x = arc4random() & 0xff;
while ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x >= '0' && x <= '9') || x == '/' || x == '+' || x == '=') {
x = arc4random() & 0xff;
}
((char*)corrupt_buffer)[i] = x;
}
dispatch_release(map);
dispatch_release(sectransform_data);
dispatch_data_t corrupt_data = dispatch_data_create(corrupt_buffer, size, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
dispatch_data_t transform_data = dispatch_data_create_with_transform(corrupt_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_null("decode64_corrupt_test: dispatch_data_create_with_transform", transform_data);
dispatch_release(corrupt_data);
close(fd);
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode64_loop_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
void
chunking_decode64_test(void * context)
{
(void)context;
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_data_t __block data = dispatch_data_empty;
int i;
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("read", 0);
for (i=0; i<4096; i++) {
dispatch_group_enter(group);
dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
assert(error == 0);
dispatch_data_t concat = dispatch_data_create_concat(data, d);
dispatch_release(data);
data = concat;
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(queue);
dispatch_release(group);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_notnull("chunking_decode64_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("chunking_decode64_test", transformed_data, data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
dispatch_release(data);
close(fd);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, decode64_corrupt_test);
}
void
chunking_encode64_test(void * context)
{
(void)context;
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_data_t __block data = dispatch_data_empty;
int i;
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("read", 0);
for (i=0; i<4097; i++) {
dispatch_group_enter(group);
dispatch_read(fd, 1, queue, ^(dispatch_data_t d, int error) {
assert(error == 0);
dispatch_data_t concat = dispatch_data_create_concat(data, d);
dispatch_release(data);
data = concat;
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(queue);
dispatch_release(group);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
test_ptr_notnull("chunking_encode64_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("chunking_encode64_test", transformed_data, sectransform_data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
dispatch_release(data);
close(fd);
dispatch_group_async_f(context, dispatch_get_main_queue(), context, chunking_decode64_test);
}
void
decode64_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transform_data = dispatch_data_create_with_transform(sectransform_data, DISPATCH_DATA_FORMAT_TYPE_BASE64, DISPATCH_DATA_FORMAT_TYPE_NONE);
test_ptr_notnull("decode64_test: dispatch_data_create_with_transform", transform_data);
test_data_equal("decode64_test", transform_data, data);
dispatch_release(sectransform_data);
dispatch_release(transform_data);
close(fd);
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, chunking_encode64_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
void
encode64_test(void * context)
{
dispatch_group_enter((dispatch_group_t)context);
int fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);
dispatch_read(fd, 4096, dispatch_get_main_queue(), ^(dispatch_data_t data, int error) {
assert(error == 0);
SecTransformRef transformRef = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
assert(transformRef);
dispatch_data_t sectransform_data = execute_sectransform(transformRef, data);
assert(sectransform_data);
CFRelease(transformRef);
dispatch_data_t transformed_data = dispatch_data_create_with_transform(data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
test_ptr_notnull("encode64_test: dispatch_data_create_with_transform", transformed_data);
test_data_equal("encode64_test", transformed_data, sectransform_data);
dispatch_release(sectransform_data);
dispatch_release(transformed_data);
close(fd);
dispatch_group_async_f((dispatch_group_t)context, dispatch_get_main_queue(), context, decode64_test);
dispatch_group_leave((dispatch_group_t)context);
});
}
#pragma mark - main
int
main(void)
{
test_start("Dispatch data transforms test");
dispatch_group_t group = dispatch_group_create();
dispatch_group_async_f(group, dispatch_get_main_queue(), group, encode64_test);
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
dispatch_release(group);
test_stop();
exit(0);
});
dispatch_main();
return 0;
}
#else
int
main(void)
{
test_skip("Dispatch data transforms test");
return 0;
}
#endif