123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862 |
- //------------------------------------------------------------------------------
- // sokol-fetch-test.c
- //
- // FIXME: simulate allocation errors
- //------------------------------------------------------------------------------
- #define SOKOL_IMPL
- #define SFETCH_MAX_USERDATA_UINT64 (8)
- #define SFETCH_MAX_PATH (32)
- #include "sokol_fetch.h"
- #include "utest.h"
- #define T(b) EXPECT_TRUE(b)
- #define TSTR(s0, s1) EXPECT_TRUE(0 == strcmp(s0,s1))
- static uint8_t load_file_buf[500000];
- static const uint64_t combatsignal_file_size = 409482;
- typedef struct {
- int a, b, c;
- } userdata_t;
- static const _sfetch_item_t zeroed_item = {0};
- #ifdef _WIN32
- #include <windows.h>
- static void sleep_ms(int ms) {
- Sleep((DWORD)ms);
- }
- #else
- #include <unistd.h>
- static void sleep_ms(uint32_t ms) {
- usleep(ms * 1000);
- }
- #endif
- /* private implementation functions */
- UTEST(sokol_fetch, path_make) {
- const char* str31 = "1234567890123456789012345678901";
- const char* str32 = "12345678901234567890123456789012";
- // max allowed string length (MAX_PATH - 1)
- _sfetch_path_t p31 = _sfetch_path_make(str31);
- TSTR(p31.buf, str31);
- // overflow
- _sfetch_path_t p32 = _sfetch_path_make(str32);
- T(p32.buf[0] == 0);
- }
- UTEST(sokol_fetch, make_id) {
- uint32_t slot_id = _sfetch_make_id(123, 456);
- T(slot_id == ((456<<16)|123));
- T(_sfetch_slot_index(slot_id) == 123);
- }
- UTEST(sokol_fetch, item_init_discard) {
- userdata_t user_data = {
- .a = 123,
- .b = 456,
- .c = 789
- };
- sfetch_request_t request = {
- .channel = 4,
- .path = "hello_world.txt",
- .chunk_size = 128,
- .user_data = SFETCH_RANGE(user_data)
- };
- _sfetch_item_t item = zeroed_item;
- uint32_t slot_id = _sfetch_make_id(1, 1);
- _sfetch_item_init(&item, slot_id, &request);
- T(item.handle.id == slot_id);
- T(item.channel == 4);
- T(item.lane == _SFETCH_INVALID_LANE);
- T(item.chunk_size == 128);
- T(item.state == _SFETCH_STATE_INITIAL);
- TSTR(item.path.buf, request.path);
- T(item.user.user_data_size == sizeof(userdata_t));
- const userdata_t* ud = (const userdata_t*) item.user.user_data;
- T((((uintptr_t)ud) & 0x7) == 0); // check alignment
- T(ud->a == 123);
- T(ud->b == 456);
- T(ud->c == 789);
- item.state = _SFETCH_STATE_FETCHING;
- _sfetch_item_discard(&item);
- T(item.handle.id == 0);
- T(item.path.buf[0] == 0);
- T(item.state == _SFETCH_STATE_INITIAL);
- T(item.user.user_data_size == 0);
- T(item.user.user_data[0] == 0);
- }
- UTEST(sokol_fetch, item_init_path_overflow) {
- sfetch_request_t request = {
- .path = "012345678901234567890123456789012",
- };
- _sfetch_item_t item = zeroed_item;
- _sfetch_item_init(&item, _sfetch_make_id(1, 1), &request);
- T(item.path.buf[0] == 0);
- }
- UTEST(sokol_fetch, item_init_userdata_overflow) {
- uint8_t big_data[128] = { 0xFF };
- sfetch_request_t request = {
- .path = "hello_world.txt",
- .user_data = SFETCH_RANGE(big_data),
- };
- _sfetch_item_t item = zeroed_item;
- _sfetch_item_init(&item, _sfetch_make_id(1, 1), &request);
- T(item.user.user_data_size == 0);
- T(item.user.user_data[0] == 0);
- }
- UTEST(sokol_fetch, pool_init_discard) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_pool_t pool = {0};
- const uint32_t num_items = 127;
- T(_sfetch_pool_init(&pool, num_items));
- T(pool.valid);
- T(pool.size == 128);
- T(pool.free_top == 127);
- T(pool.free_slots[0] == 127);
- T(pool.free_slots[1] == 126);
- T(pool.free_slots[126] == 1);
- _sfetch_pool_discard(&pool);
- T(!pool.valid);
- T(pool.free_slots == 0);
- T(pool.items == 0);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, pool_alloc_free) {
- sfetch_setup(&(sfetch_desc_t){0});
- uint8_t buf[32];
- _sfetch_pool_t pool = {0};
- const uint32_t num_items = 16;
- _sfetch_pool_init(&pool, num_items);
- uint32_t slot_id = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){
- .path = "hello_world.txt",
- .buffer = SFETCH_RANGE(buf),
- });
- T(slot_id == 0x00010001);
- T(pool.items[1].state == _SFETCH_STATE_ALLOCATED);
- T(pool.items[1].handle.id == slot_id);
- TSTR(pool.items[1].path.buf, "hello_world.txt");
- T(pool.items[1].buffer.ptr == buf);
- T(pool.items[1].buffer.size == sizeof(buf));
- T(pool.free_top == 15);
- _sfetch_pool_item_free(&pool, slot_id);
- T(pool.items[1].handle.id == 0);
- T(pool.items[1].state == _SFETCH_STATE_INITIAL);
- T(pool.items[1].path.buf[0] == 0);
- T(pool.items[1].buffer.ptr == 0);
- T(pool.items[1].buffer.size == 0);
- T(pool.free_top == 16);
- _sfetch_pool_discard(&pool);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, pool_overflow) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_pool_t pool = {0};
- _sfetch_pool_init(&pool, 4);
- uint32_t id0 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path0" });
- uint32_t id1 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path1" });
- uint32_t id2 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path2" });
- uint32_t id3 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path3" });
- // next alloc should fail
- uint32_t id4 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path4" });
- T(id0 == 0x00010001);
- T(id1 == 0x00010002);
- T(id2 == 0x00010003);
- T(id3 == 0x00010004);
- T(id4 == 0);
- T(pool.items[1].handle.id == id0);
- T(pool.items[2].handle.id == id1);
- T(pool.items[3].handle.id == id2);
- T(pool.items[4].handle.id == id3);
- // free one item, alloc should work now
- _sfetch_pool_item_free(&pool, id0);
- uint32_t id5 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path5" });
- T(id5 == 0x00020001);
- T(pool.items[1].handle.id == id5);
- TSTR(pool.items[1].path.buf, "path5");
- _sfetch_pool_discard(&pool);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, lookup_item) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_pool_t pool = {0};
- _sfetch_pool_init(&pool, 4);
- uint32_t id0 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path0" });
- uint32_t id1 = _sfetch_pool_item_alloc(&pool, &(sfetch_request_t){ .path="path1" });
- const _sfetch_item_t* item0 = _sfetch_pool_item_lookup(&pool, id0);
- const _sfetch_item_t* item1 = _sfetch_pool_item_lookup(&pool, id1);
- T(item0 == &pool.items[1]);
- T(item1 == &pool.items[2]);
- /* invalid handle always returns 0-ptr */
- T(0 == _sfetch_pool_item_lookup(&pool, _sfetch_make_id(0, 0)));
- /* free an item and make sure it's detected as dangling */
- _sfetch_pool_item_free(&pool, id0);
- T(0 == _sfetch_pool_item_lookup(&pool, id0));
- _sfetch_pool_discard(&pool);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, ring_init_discard) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_ring_t ring = {0};
- const uint32_t num_slots = 4;
- T(_sfetch_ring_init(&ring, num_slots));
- T(ring.head == 0);
- T(ring.tail == 0);
- T(ring.num == (num_slots + 1));
- T(ring.buf);
- _sfetch_ring_discard(&ring);
- T(ring.head == 0);
- T(ring.tail == 0);
- T(ring.num == 0);
- T(ring.buf == 0);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, ring_enqueue_dequeue) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_ring_t ring = {0};
- const uint32_t num_slots = 4;
- _sfetch_ring_init(&ring, num_slots);
- T(_sfetch_ring_count(&ring) == 0);
- T(_sfetch_ring_empty(&ring));
- T(!_sfetch_ring_full(&ring));
- for (uint32_t i = 0; i < num_slots; i++) {
- T(!_sfetch_ring_full(&ring));
- _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1));
- T(_sfetch_ring_count(&ring) == (i+1));
- T(!_sfetch_ring_empty(&ring));
- }
- T(_sfetch_ring_count(&ring) == 4);
- T(!_sfetch_ring_empty(&ring));
- T(_sfetch_ring_full(&ring));
- for (uint32_t i = 0; i < num_slots; i++) {
- T(_sfetch_ring_peek(&ring, i) == _sfetch_make_id(1, i+1));
- }
- for (uint32_t i = 0; i < num_slots; i++) {
- T(!_sfetch_ring_empty(&ring));
- const uint32_t slot_id = _sfetch_ring_dequeue(&ring);
- T(slot_id == _sfetch_make_id(1, i+1));
- T(!_sfetch_ring_full(&ring));
- }
- T(_sfetch_ring_count(&ring) == 0);
- T(_sfetch_ring_empty(&ring));
- T(!_sfetch_ring_full(&ring));
- _sfetch_ring_discard(&ring);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, ring_wrap_around) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_ring_t ring = {0};
- _sfetch_ring_init(&ring, 4);
- uint32_t i = 0;
- for (i = 0; i < 4; i++) {
- _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1));
- }
- T(_sfetch_ring_full(&ring));
- for (; i < 64; i++) {
- T(_sfetch_ring_full(&ring));
- T(_sfetch_ring_dequeue(&ring) == _sfetch_make_id(1, (i - 3)));
- T(!_sfetch_ring_full(&ring));
- _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1));
- }
- T(_sfetch_ring_full(&ring));
- for (i = 0; i < 4; i++) {
- T(_sfetch_ring_dequeue(&ring) == _sfetch_make_id(1, (i + 61)));
- }
- T(_sfetch_ring_empty(&ring));
- _sfetch_ring_discard(&ring);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, ring_wrap_count) {
- sfetch_setup(&(sfetch_desc_t){0});
- _sfetch_ring_t ring = {0};
- _sfetch_ring_init(&ring, 8);
- // add and remove 4 items to move tail to the middle
- for (uint32_t i = 0; i < 4; i++) {
- _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1));
- _sfetch_ring_dequeue(&ring);
- T(_sfetch_ring_empty(&ring));
- }
- // add another 8 items
- for (uint32_t i = 0; i < 8; i++) {
- _sfetch_ring_enqueue(&ring, _sfetch_make_id(1, i+1));
- }
- // now test, dequeue and test...
- T(_sfetch_ring_full(&ring));
- for (uint32_t i = 0; i < 8; i++) {
- T(_sfetch_ring_count(&ring) == (8 - i));
- _sfetch_ring_dequeue(&ring);
- }
- T(_sfetch_ring_count(&ring) == 0);
- T(_sfetch_ring_empty(&ring));
- _sfetch_ring_discard(&ring);
- sfetch_shutdown();
- }
- /* NOTE: channel_worker is called from a thread */
- static int num_processed_items = 0;
- static void channel_worker(_sfetch_t* ctx, uint32_t slot_id) {
- (void)ctx;
- (void)slot_id;
- num_processed_items++;
- }
- UTEST(sokol_fetch, channel_init_discard) {
- sfetch_setup(&(sfetch_desc_t){0});
- num_processed_items = 0;
- _sfetch_channel_t chn = {0};
- const uint32_t num_slots = 12;
- const uint32_t num_lanes = 64;
- _sfetch_channel_init(&chn, 0, num_slots, num_lanes, channel_worker);
- T(chn.valid);
- T(_sfetch_ring_full(&chn.free_lanes));
- T(_sfetch_ring_empty(&chn.user_sent));
- T(_sfetch_ring_empty(&chn.user_incoming));
- #if !defined(__EMSCRIPTEN__)
- T(_sfetch_ring_empty(&chn.thread_incoming));
- T(_sfetch_ring_empty(&chn.thread_outgoing));
- #endif
- T(_sfetch_ring_empty(&chn.user_outgoing));
- _sfetch_channel_discard(&chn);
- T(!chn.valid);
- sfetch_shutdown();
- }
- /* public API functions */
- UTEST(sokol_fetch, setup_shutdown) {
- sfetch_setup(&(sfetch_desc_t){0});
- T(sfetch_valid());
- // check default values
- T(sfetch_desc().max_requests == 128);
- T(sfetch_desc().num_channels == 1);
- T(sfetch_desc().num_lanes == 1);
- sfetch_shutdown();
- T(!sfetch_valid());
- }
- UTEST(sokol_fetch, setup_too_many_channels) {
- /* try to initialize with too many channels, this should clamp to
- SFETCH_MAX_CHANNELS
- */
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 64
- });
- T(sfetch_valid());
- T(sfetch_desc().num_channels == SFETCH_MAX_CHANNELS);
- sfetch_shutdown();
- }
- UTEST(sokol_fetch, max_path) {
- T(sfetch_max_path() == SFETCH_MAX_PATH);
- }
- UTEST(sokol_fetch, max_userdata) {
- T(sfetch_max_userdata_bytes() == (SFETCH_MAX_USERDATA_UINT64 * sizeof(uint64_t)));
- }
- static uint8_t fail_open_buffer[128];
- static bool fail_open_passed;
- static void fail_open_callback(const sfetch_response_t* response) {
- /* if opening a file fails, it will immediate switch into CLOSED state */
- if ((response->failed) && (response->error_code == SFETCH_ERROR_FILE_NOT_FOUND)) {
- fail_open_passed = true;
- }
- }
- UTEST(sokol_fetch, fail_open) {
- sfetch_setup(&(sfetch_desc_t){0});
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "non_existing_file.txt",
- .callback = fail_open_callback,
- .buffer = SFETCH_RANGE(fail_open_buffer),
- });
- fail_open_passed = false;
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(fail_open_passed);
- sfetch_shutdown();
- }
- static bool load_file_fixed_buffer_passed;
- // The file callback is called from the "current user thread" (the same
- // thread where the sfetch_send() for this request was called). Note that you
- // can call sfetch_setup/shutdown() on multiple threads, each thread will
- // get its own thread-local "sokol-fetch instance" and its own set of
- // IO-channel threads.
- static void load_file_fixed_buffer_callback(const sfetch_response_t* response) {
- // when loading the whole file at once, the fetched state
- // is the best place to grab/process the data
- if (response->fetched) {
- if ((response->data_offset == 0) &&
- (response->data.ptr == load_file_buf) &&
- (response->data.size == combatsignal_file_size) &&
- (response->buffer.ptr == load_file_buf) &&
- (response->buffer.size == sizeof(load_file_buf)) &&
- response->finished)
- {
- load_file_fixed_buffer_passed = true;
- }
- }
- }
- UTEST(sokol_fetch, load_file_fixed_buffer) {
- memset(load_file_buf, 0, sizeof(load_file_buf));
- sfetch_setup(&(sfetch_desc_t){0});
- // send a load-request for a file where we know the max size upfront,
- // so we can provide a buffer right in the fetch request (otherwise
- // the buffer needs to be provided in the callback when the request
- // is in OPENED state, since only then the file size will be known).
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_fixed_buffer_callback,
- .buffer = SFETCH_RANGE(load_file_buf),
- });
- // simulate a frame-loop for as long as the request is in flight, normally
- // the sfetch_dowork() function is just called somewhere in the frame
- // to pump messages in and out of the IO threads, and invoke user-callbacks
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_fixed_buffer_passed);
- sfetch_shutdown();
- }
- /* tests whether files with unknown size are processed correctly */
- static bool load_file_unknown_size_opened_passed;
- static bool load_file_unknown_size_fetched_passed;
- static void load_file_unknown_size_callback(const sfetch_response_t* response) {
- if (response->dispatched) {
- if ((response->data_offset == 0) &&
- (response->data.ptr == 0) &&
- (response->data.size == 0) &&
- (response->buffer.ptr == 0) &&
- (response->buffer.size == 0) &&
- !response->finished)
- {
- load_file_unknown_size_opened_passed = true;
- sfetch_bind_buffer(response->handle, SFETCH_RANGE(load_file_buf));
- }
- }
- else if (response->fetched) {
- if ((response->data_offset == 0) &&
- (response->data.ptr == load_file_buf) &&
- (response->data.size == combatsignal_file_size) &&
- (response->buffer.ptr == load_file_buf) &&
- (response->buffer.size == sizeof(load_file_buf)) &&
- response->finished)
- {
- load_file_unknown_size_fetched_passed = true;
- }
- }
- }
- UTEST(sokol_fetch, load_file_unknown_size) {
- memset(load_file_buf, 0, sizeof(load_file_buf));
- sfetch_setup(&(sfetch_desc_t){0});
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_unknown_size_callback
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_unknown_size_opened_passed);
- T(load_file_unknown_size_fetched_passed);
- sfetch_shutdown();
- }
- /* tests whether not providing a buffer in OPENED properly fails */
- static bool load_file_no_buffer_opened_passed;
- static bool load_file_no_buffer_failed_passed;
- static void load_file_no_buffer_callback(const sfetch_response_t* response) {
- if (response->dispatched) {
- if ((response->data_offset == 0) &&
- (response->data.ptr == 0) &&
- (response->data.size == 0) &&
- (response->buffer.ptr == 0) &&
- (response->buffer.size == 0) &&
- !response->finished)
- {
- /* DO NOT provide a buffer here, see if that properly fails */
- load_file_no_buffer_opened_passed = true;
- }
- }
- else if ((response->failed) && (response->error_code == SFETCH_ERROR_NO_BUFFER)) {
- if (load_file_no_buffer_opened_passed) {
- load_file_no_buffer_failed_passed = true;
- }
- }
- }
- UTEST(sokol_fetch, load_file_no_buffer) {
- memset(load_file_buf, 0, sizeof(load_file_buf));
- sfetch_setup(&(sfetch_desc_t){0});
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_no_buffer_callback
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_no_buffer_opened_passed);
- T(load_file_no_buffer_failed_passed);
- sfetch_shutdown();
- }
- static bool load_file_too_small_passed;
- static uint8_t load_file_too_small_buf[8192];
- static void load_file_too_small_callback(const sfetch_response_t* response) {
- if (response->failed && (response->error_code == SFETCH_ERROR_BUFFER_TOO_SMALL)) {
- load_file_too_small_passed = true;
- }
- }
- UTEST(sokol_fetch, load_file_too_small_buffer) {
- memset(load_file_buf, 0, sizeof(load_file_buf));
- sfetch_setup(&(sfetch_desc_t){0});
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_too_small_callback,
- .buffer = SFETCH_RANGE(load_file_too_small_buf),
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_too_small_passed);
- sfetch_shutdown();
- }
- /* test loading a big file via a small chunk-buffer, the callback will
- be called multiple times with the FETCHED state until the entire file
- is loaded
- */
- static bool load_file_chunked_passed;
- static uint8_t load_chunk_buf[8192];
- static uint8_t load_file_chunked_content[500000];
- static void load_file_chunked_callback(const sfetch_response_t* response) {
- if (response->fetched) {
- uint8_t* dst = &load_file_chunked_content[response->data_offset];
- const uint8_t* src = response->data.ptr;
- size_t num_bytes = response->data.size;
- memcpy(dst, src, num_bytes);
- if (response->finished) {
- load_file_chunked_passed = true;
- }
- }
- }
- UTEST(sokol_fetch, load_file_chunked) {
- memset(load_file_buf, 0, sizeof(load_file_buf));
- memset(load_chunk_buf, 0, sizeof(load_chunk_buf));
- memset(load_file_chunked_content, 0, sizeof(load_file_chunked_content));
- load_file_fixed_buffer_passed = false;
- sfetch_setup(&(sfetch_desc_t){0});
- // request for chunked-loading
- sfetch_handle_t h0 = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_chunked_callback,
- .buffer = SFETCH_RANGE(load_chunk_buf),
- .chunk_size = sizeof(load_chunk_buf)
- });
- // request for all-in-one loading for comparing with the chunked buffer
- sfetch_handle_t h1 = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_fixed_buffer_callback,
- .buffer = SFETCH_RANGE(load_file_buf),
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while ((sfetch_handle_valid(h0) || sfetch_handle_valid(h1)) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_chunked_passed);
- T(0 == memcmp(load_file_chunked_content, load_file_buf, combatsignal_file_size));
- sfetch_shutdown();
- }
- /* load N big files in small chunks interleaved on the same channel via lanes */
- #define LOAD_FILE_LANES_NUM_LANES (4)
- static uint8_t load_file_lanes_chunk_buf[LOAD_FILE_LANES_NUM_LANES][8192];
- static uint8_t load_file_lanes_content[LOAD_FILE_LANES_NUM_LANES][500000];
- static int load_file_lanes_passed[LOAD_FILE_LANES_NUM_LANES];
- static void load_file_lanes_callback(const sfetch_response_t* response) {
- assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES));
- if (response->fetched) {
- uint8_t* dst = &load_file_lanes_content[response->lane][response->data_offset];
- const uint8_t* src = response->data.ptr;
- size_t num_bytes = response->data.size;
- memcpy(dst, src, num_bytes);
- if (response->finished) {
- load_file_lanes_passed[response->lane]++;
- }
- }
- }
- UTEST(sokol_fetch, load_file_lanes) {
- for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) {
- memset(load_file_lanes_content[i], i, sizeof(load_file_lanes_content[i]));
- }
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 1,
- .num_lanes = LOAD_FILE_LANES_NUM_LANES,
- });
- sfetch_handle_t h[LOAD_FILE_LANES_NUM_LANES];
- for (int lane = 0; lane < LOAD_FILE_LANES_NUM_LANES; lane++) {
- h[lane] = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_lanes_callback,
- .buffer = { .ptr = load_file_lanes_chunk_buf[lane], .size = sizeof(load_file_lanes_chunk_buf[0]) },
- .chunk_size = sizeof(load_file_lanes_chunk_buf[0])
- });
- }
- bool done = false;
- int frame_count = 0;
- const int max_frames = 10000;
- while (!done && (frame_count++ < max_frames)) {
- done = true;
- for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) {
- done &= !sfetch_handle_valid(h[i]);
- }
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- for (int i = 0; i < LOAD_FILE_LANES_NUM_LANES; i++) {
- T(1 == load_file_lanes_passed[i]);
- T(0 == memcmp(load_file_lanes_content[0], load_file_lanes_content[i], combatsignal_file_size));
- }
- sfetch_shutdown();
- }
- /* same as above, but issue more requests than available lanes to test if rate-limiting works */
- #define LOAD_FILE_THROTTLE_NUM_LANES (4)
- #define LOAD_FILE_THROTTLE_NUM_PASSES (3)
- #define LOAD_FILE_THROTTLE_NUM_REQUESTS (12) // lanes * passes
- static uint8_t load_file_throttle_chunk_buf[LOAD_FILE_THROTTLE_NUM_LANES][128000];
- static uint8_t load_file_throttle_content[LOAD_FILE_THROTTLE_NUM_PASSES][LOAD_FILE_THROTTLE_NUM_LANES][500000];
- static int load_file_throttle_passed[LOAD_FILE_THROTTLE_NUM_LANES];
- static void load_file_throttle_callback(const sfetch_response_t* response) {
- assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES));
- if (response->fetched) {
- assert(load_file_throttle_passed[response->lane] < LOAD_FILE_THROTTLE_NUM_PASSES);
- uint8_t* dst = &load_file_throttle_content[load_file_throttle_passed[response->lane]][response->lane][response->data_offset];
- const uint8_t* src = response->data.ptr;
- size_t num_bytes = response->data.size;
- memcpy(dst, src, num_bytes);
- if (response->finished) {
- load_file_throttle_passed[response->lane]++;
- }
- }
- }
- UTEST(sokol_fetch, load_file_throttle) {
- for (int pass = 0; pass < LOAD_FILE_THROTTLE_NUM_PASSES; pass++) {
- for (int lane = 0; lane < LOAD_FILE_THROTTLE_NUM_LANES; lane++) {
- memset(load_file_throttle_content[pass][lane], 10*pass+lane, sizeof(load_file_throttle_content[pass][lane]));
- }
- }
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 1,
- .num_lanes = LOAD_FILE_THROTTLE_NUM_LANES,
- });
- sfetch_handle_t h[LOAD_FILE_THROTTLE_NUM_REQUESTS];
- for (int i = 0; i < LOAD_FILE_THROTTLE_NUM_REQUESTS; i++) {
- h[i] = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_throttle_callback,
- .buffer = {
- .ptr = load_file_throttle_chunk_buf[i % LOAD_FILE_THROTTLE_NUM_LANES],
- .size = sizeof(load_file_throttle_chunk_buf[0]),
- },
- .chunk_size = sizeof(load_file_throttle_chunk_buf[0])
- });
- T(sfetch_handle_valid(h[i]));
- }
- bool done = false;
- int frame_count = 0;
- const int max_frames = 10000;
- while (!done && (frame_count++ < max_frames)) {
- done = true;
- for (int i = 0; i < LOAD_FILE_THROTTLE_NUM_REQUESTS; i++) {
- done &= !sfetch_handle_valid(h[i]);
- }
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- for (int lane = 0; lane < LOAD_FILE_THROTTLE_NUM_LANES; lane++) {
- T(LOAD_FILE_THROTTLE_NUM_PASSES == load_file_throttle_passed[lane]);
- for (int pass = 0; pass < LOAD_FILE_THROTTLE_NUM_PASSES; pass++) {
- T(0 == memcmp(load_file_throttle_content[0][0], load_file_throttle_content[pass][lane], combatsignal_file_size));
- }
- }
- sfetch_shutdown();
- }
- /* test parallel fetches on multiple channels */
- #define LOAD_CHANNEL_NUM_CHANNELS (16)
- static uint8_t load_channel_buf[LOAD_CHANNEL_NUM_CHANNELS][500000];
- static bool load_channel_passed[LOAD_CHANNEL_NUM_CHANNELS];
- void load_channel_callback(const sfetch_response_t* response) {
- assert(response->channel < LOAD_CHANNEL_NUM_CHANNELS);
- assert(!load_channel_passed[response->channel]);
- if (response->fetched) {
- if ((response->data.size == combatsignal_file_size) && response->finished) {
- load_channel_passed[response->channel] = true;
- }
- }
- }
- UTEST(sokol_fetch, load_channel) {
- for (int chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) {
- memset(load_channel_buf[chn], chn, sizeof(load_channel_buf[chn]));
- }
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = LOAD_CHANNEL_NUM_CHANNELS
- });
- sfetch_handle_t h[LOAD_CHANNEL_NUM_CHANNELS];
- for (uint32_t chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) {
- h[chn] = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .channel = chn,
- .callback = load_channel_callback,
- .buffer = SFETCH_RANGE(load_channel_buf[chn]),
- });
- }
- bool done = false;
- int frame_count = 0;
- const int max_frames = 100000;
- while (!done && (frame_count++ < max_frames)) {
- done = true;
- for (int i = 0; i < LOAD_CHANNEL_NUM_CHANNELS; i++) {
- done &= !sfetch_handle_valid(h[i]);
- }
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- for (int chn = 0; chn < LOAD_CHANNEL_NUM_CHANNELS; chn++) {
- T(load_channel_passed[chn]);
- T(0 == memcmp(load_channel_buf[0], load_channel_buf[chn], combatsignal_file_size));
- }
- sfetch_shutdown();
- }
- static bool load_file_cancel_passed = false;
- static void load_file_cancel_callback(const sfetch_response_t* response) {
- if (response->dispatched) {
- sfetch_cancel(response->handle);
- }
- if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) {
- load_file_cancel_passed = true;
- }
- }
- UTEST(sokol_fetch, load_file_cancel) {
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 1
- });
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_cancel_callback,
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_cancel_passed);
- sfetch_shutdown();
- }
- static bool load_file_cancel_before_dispatch_passed = false;
- static void load_file_cancel_before_dispatch_callback(const sfetch_response_t* response) {
- // cancelled, finished, failed and error code must all be set
- if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) {
- load_file_cancel_before_dispatch_passed = true;
- }
- }
- UTEST(sokol_fetch, load_file_cancel_before_dispatch) {
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 1,
- });
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_cancel_before_dispatch_callback,
- });
- sfetch_cancel(h);
- sfetch_dowork();
- T(load_file_cancel_before_dispatch_passed);
- sfetch_shutdown();
- }
- static bool load_file_cancel_after_dispatch_passed = false;
- static void load_file_cancel_after_dispatch_callback(const sfetch_response_t* response) {
- // when cancelled, then finished, failed and error code must all be set
- if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) {
- load_file_cancel_after_dispatch_passed = true;
- }
- }
- UTEST(sokol_fetch, load_file_cancel_after_dispatch) {
- sfetch_setup(&(sfetch_desc_t){
- .num_channels = 1,
- });
- sfetch_handle_t h = sfetch_send(&(sfetch_request_t){
- .path = "comsi.s3m",
- .callback = load_file_cancel_after_dispatch_callback,
- .buffer = SFETCH_RANGE(load_file_buf),
- });
- int frame_count = 0;
- const int max_frames = 10000;
- while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) {
- sfetch_dowork();
- sfetch_cancel(h);
- sleep_ms(1);
- }
- T(frame_count < max_frames);
- T(load_file_cancel_after_dispatch_passed);
- sfetch_shutdown();
- }
|