Skip to content

Commit

Permalink
More dispatch tests and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gershnik committed Dec 7, 2023
1 parent 01de2c5 commit d6a1b8b
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 12 deletions.
22 changes: 12 additions & 10 deletions include/objc-helpers/CoDispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,14 +634,13 @@ struct IOResult {
int error;
};

struct IOPartialResult : IOResult {
bool done;
};

inline auto co_dispatch_io_read(dispatch_io_t channel, off_t offset, size_t length, dispatch_queue_t queue) {
return DispatchAwaitable<IOPartialResult, SupportsExceptions::No>::invokeDirectly([channel, offset, length, queue](auto promise) {
inline auto co_dispatch_io_read(dispatch_io_t channel, off_t offset, size_t length, dispatch_queue_t queue, dispatch_io_handler_t progressHandler = nullptr) {
return DispatchAwaitable<IOResult, SupportsExceptions::No>::invokeDirectly([channel, offset, length, queue, progressHandler](auto promise) {
dispatch_io_read(channel, offset, length, queue, ^ (bool done, dispatch_data_t data, int error){
promise.success({{data, error}, done});
if (progressHandler)
progressHandler(done, data, error);
if (done)
promise.success({data, error});
});
});
}
Expand All @@ -654,10 +653,13 @@ inline auto co_dispatch_read(dispatch_fd_t fd, size_t length, dispatch_queue_t q
});
}

inline auto co_dispatch_io_write(dispatch_io_t channel, off_t offset, dispatch_data_t data, dispatch_queue_t queue) {
return DispatchAwaitable<IOPartialResult, SupportsExceptions::No>::invokeDirectly([channel, offset, data, queue](auto promise) {
inline auto co_dispatch_io_write(dispatch_io_t channel, off_t offset, dispatch_data_t data, dispatch_queue_t queue, dispatch_io_handler_t progressHandler = nullptr) {
return DispatchAwaitable<IOResult, SupportsExceptions::No>::invokeDirectly([channel, offset, data, queue, progressHandler](auto promise) {
dispatch_io_write(channel, offset, data, queue, ^ (bool done, dispatch_data_t dataRemaining, int error){
promise.success({{dataRemaining, error}, done});
if (progressHandler)
progressHandler(done, data, error);
if (done)
promise.success({dataRemaining, error});
});
});
}
Expand Down
129 changes: 128 additions & 1 deletion test/CoDispatchTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
#include "doctest.h"

#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>

#include <string>
#include <string_view>
#include <map>
#include <filesystem>

template<class T>
struct Sequence {
Expand Down Expand Up @@ -322,6 +324,25 @@ static auto checkMakeAwaitable() -> DispatchTask<> {
CHECK(strcmp(ex.what(), "hoho") == 0);
}

{
struct Thrower {
Thrower(int) {
throw std::logic_error("bam");
}
};

try {
co_await makeAwaitable<Thrower>([](auto promise) {
dispatch_async(dispatch_get_main_queue(), ^ () {
promise.success(6);
});
});
FAIL("exception not thrown");
} catch (std::logic_error & ex) {
CHECK(strcmp(ex.what(), "bam") == 0);
}
}

{

struct Foo {
Expand Down Expand Up @@ -358,19 +379,125 @@ static auto checkMakeAwaitable() -> DispatchTask<> {
}
}

static auto checkTasks() -> DispatchTask<> {

auto exceptor = []() -> DispatchTask<int> {
auto conq = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);

co_await resumeOn(conq);
throw std::runtime_error("whopwhop");
};

try {
co_await exceptor();
FAIL("exception not thrown");
} catch (std::runtime_error & ex) {
CHECK(strcmp(ex.what(), "whopwhop") == 0);
}

co_await resumeOnMainQueue();


auto coro = []() -> DispatchTask<int> {
auto conq = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);

co_await resumeOn(conq);
co_return 25;
};

co_await coro().resumeOnMainQueue();
}

static auto checkIO() -> DispatchTask<> {

auto conq = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);

co_await resumeOn(conq);

char buf[1024];
uint32_t size = sizeof(buf);
REQUIRE(_NSGetExecutablePath(buf, &size) == 0);
std::filesystem::path path(buf);
path = path.parent_path() / "test.txt";

dispatch_data_t hello = dispatch_data_create("hello", 5, conq, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
dispatch_data_t world = dispatch_data_create(" world", 6, conq, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
dispatch_data_t yada = dispatch_data_create(" yada", 5, conq, DISPATCH_DATA_DESTRUCTOR_DEFAULT);

{
int wfd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR);
REQUIRE(wfd);

auto res = co_await co_dispatch_write(wfd, hello, conq);
REQUIRE(!res.error);
dispatch_io_t wch = dispatch_io_create(DISPATCH_IO_STREAM, wfd, conq, ^(int /*error*/) {
close(wfd);
});
res = co_await co_dispatch_io_write(wch, 5, world, conq);
REQUIRE(!res.error);
__block int count = 0;
res = co_await co_dispatch_io_write(wch, 11, yada, conq, ^ (bool done, dispatch_data_t data, int error) {
++count;
});
REQUIRE(!res.error);
CHECK(count > 0);
}

{
int rfd = open(path.c_str(), O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR);
REQUIRE(rfd);

auto res = co_await co_dispatch_read(rfd, 5, conq);
REQUIRE(!res.error);
REQUIRE((res.data != nullptr));
auto combined = res.data;

dispatch_io_t rch = dispatch_io_create(DISPATCH_IO_STREAM, rfd, conq, ^(int /*error*/) {
close(rfd);
});

res = co_await co_dispatch_io_read(rch, 5, 6, conq);
REQUIRE(!res.error);
REQUIRE((res.data != nullptr));

combined = dispatch_data_create_concat(combined, res.data);
__block int count = 0;
res = co_await co_dispatch_io_read(rch, 11, 5, conq, ^ (bool done, dispatch_data_t data, int error) {
++count;
});
REQUIRE(!res.error);
REQUIRE((res.data != nullptr));
CHECK(count > 0);

combined = dispatch_data_create_concat(combined, res.data);

//CHECK(dispatch_data_get_size(combined) == 16);
const void * realData;
size_t realSize;
[[maybe_unused]] dispatch_data_t dumb = dispatch_data_create_map(combined, &realData, &realSize);
CHECK(realSize == 16);
CHECK(memcmp(realData, "hello world yada", 16) == 0);
}

remove(path);

co_await resumeOnMainQueue();
}

static DispatchTask<> runTests(bool & shouldKeepRunning) {

co_await checkReturnPropagation();
co_await checkDispatchToDifferentQueue();
co_await checkMakeAwaitable();
co_await checkTasks();
co_await checkIO();

shouldKeepRunning = false;
}


TEST_CASE("CoDispatchTests") {


bool shouldKeepRunning = true;

runTests(shouldKeepRunning);
Expand Down
2 changes: 1 addition & 1 deletion test/test.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "LLVM_PROFILE_FILE=$CONFIGURATION_BUILD_DIR/test.profraw $BUILT_PRODUCTS_DIR/test\nllvm-profdata merge -sparse $CONFIGURATION_BUILD_DIR/test.profraw -o $CONFIGURATION_BUILD_DIR/test.profdata\nllvm-cov show -format=html \\\n -arch `uname -m` \\\n -Xdemangler=c++filt -Xdemangler -n \\\n -show-regions=1 \\\n -show-instantiations=1 \\\n -ignore-filename-regex=test/.\\\\\\\\* \\\n -ignore-filename-regex=doctest\\\\.h \\\n -output-dir=$BUILT_PRODUCTS_DIR/coverage \\\n -instr-profile=$CONFIGURATION_BUILD_DIR/test.profdata \\\n $BUILT_PRODUCTS_DIR/test\n#-show-branches=count\n#-show-instantiation-summary=1\nopen file://$BUILT_PRODUCTS_DIR/coverage/index.html\n \n";
shellScript = "LLVM_PROFILE_FILE=$CONFIGURATION_BUILD_DIR/test.profraw $BUILT_PRODUCTS_DIR/test\nllvm-profdata merge -sparse $CONFIGURATION_BUILD_DIR/test.profraw -o $CONFIGURATION_BUILD_DIR/test.profdata\nllvm-cov show -format=html \\\n -arch `uname -m` \\\n -Xdemangler=c++filt -Xdemangler -n \\\n -show-regions=1 \\\n -show-instantiations=0 \\\n -ignore-filename-regex=test/.\\\\\\\\* \\\n -ignore-filename-regex=doctest\\\\.h \\\n -output-dir=$BUILT_PRODUCTS_DIR/coverage \\\n -instr-profile=$CONFIGURATION_BUILD_DIR/test.profdata \\\n $BUILT_PRODUCTS_DIR/test\n#-show-branches=count\n#-show-instantiation-summary=1\nopen file://$BUILT_PRODUCTS_DIR/coverage/index.html\n \n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down

0 comments on commit d6a1b8b

Please sign in to comment.