diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc96b793..e39129b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,36 +4,6 @@ on: tags: - '*' jobs: - run-tests: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - build-essential \ - cmake \ - python3 \ - python3-pip \ - python3-polib \ - python3-pil \ - libsdl2-dev \ - libgl1-mesa-dev \ - libzip-dev \ - python3-dotenv \ - python3-pyqt5 \ - python3-opengl \ - xz-utils \ - liblzma-dev \ - libbz2-dev \ - zlib1g-dev \ - git \ - libssl-dev - - name: Run tests - run: ./scripts/test-linux.sh - build-linux: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..f2cbf7af --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,35 @@ +name: Test Dusk +on: + pull_request: + branches: + - main +jobs: + run-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + cmake \ + python3 \ + python3-pip \ + python3-polib \ + python3-pil \ + libsdl2-dev \ + libgl1-mesa-dev \ + libzip-dev \ + python3-dotenv \ + python3-pyqt5 \ + python3-opengl \ + xz-utils \ + liblzma-dev \ + libbz2-dev \ + zlib1g-dev \ + git \ + libssl-dev + - name: Run tests + run: ./scripts/test-linux.sh diff --git a/src/dusk/asset/loader/locale/assetlocaleloader.c b/src/dusk/asset/loader/locale/assetlocaleloader.c index 6d7a825c..5c4034b1 100644 --- a/src/dusk/asset/loader/locale/assetlocaleloader.c +++ b/src/dusk/asset/loader/locale/assetlocaleloader.c @@ -506,6 +506,10 @@ errorret_t assetLocaleGetString( sizeof(lineBuffer) ); + // Prime the reader with the first line before scanning; outBuffer holds + // uninitialized memory until the first Next() call fills it. + errorChain(assetFileLineReaderNext(&reader)); + // Skip blanks, comments, etc and start looking for msgid's errorChain(assetLocaleLineSkipBlanks(&reader, lineBuffer)); diff --git a/test/asset/test_asset.c b/test/asset/test_asset.c index 0ff4d9ef..bdac1404 100644 --- a/test/asset/test_asset.c +++ b/test/asset/test_asset.c @@ -133,21 +133,22 @@ static void test_update_entry_reaches_loaded(void **state) { assert_int_equal(memoryGetAllocatedCount(), 0); } -static void test_update_slot_occupied_after_first_update(void **state) { +static void test_update_slot_cleared_after_first_update(void **state) { assetentry_t *entry = assetGetEntry("test.locale", ASSET_LOADER_TYPE_LOCALE, NULL); assetEntryLock(entry); assetUpdate(); assert_int_equal(entry->state, ASSET_ENTRY_STATE_LOADED); - // Slot not cleared until the second update processes the LOADED case. - assert_true(loading_slot_has_entry(entry)); + // A synchronous load clears its own loading slot in the same update call + // that completes it, so no second update is needed to free it. + assert_false(loading_slot_has_entry(entry)); assetEntryUnlock(entry); assert_int_equal(memoryGetAllocatedCount(), 0); } -static void test_update_slot_cleared_after_second_update(void **state) { +static void test_update_slot_stays_cleared_on_further_updates(void **state) { assetentry_t *entry = assetGetEntry("test.locale", ASSET_LOADER_TYPE_LOCALE, NULL); assetEntryLock(entry); @@ -238,13 +239,17 @@ static void test_update_overflow_queues_entries(void **state) { entries[i] = assetGetEntry(name, ASSET_LOADER_TYPE_LOCALE, NULL); } - // Lock first batch so the reaper won't collect them before we check. - for(int i = 0; i < ASSET_LOADING_COUNT_MAX; i++) { + // Lock every entry, including the overflow one, so the reaper won't + // collect any of them - a synchronous load can reach LOADED and free its + // slot within the same update call the reaper runs in. + for(int i = 0; i < TOTAL; i++) { assetEntryLock(entries[i]); } - // Update 1: fills all slots, first ASSET_LOADING_COUNT_MAX entries reach LOADED. - // The overflow entry has no slot yet and stays NOT_STARTED. + // Update 1: fills all slots, first ASSET_LOADING_COUNT_MAX entries reach + // LOADED and immediately free their slots. The overflow entry has no slot + // yet because dispatch ran before this update's turn began, so it stays + // NOT_STARTED. errorret_t ret = assetUpdate(); assert_true(errorIsOk(ret)); for(int i = 0; i < ASSET_LOADING_COUNT_MAX; i++) { @@ -252,26 +257,15 @@ static void test_update_overflow_queues_entries(void **state) { } assert_int_equal(entries[ASSET_LOADING_COUNT_MAX]->state, ASSET_ENTRY_STATE_NOT_STARTED); - // Unlock first batch - the reaper can collect them in update 2. - for(int i = 0; i < ASSET_LOADING_COUNT_MAX; i++) { - assetEntryUnlock(entries[i]); - } - - // Update 2: LOADED slots are freed. Overflow entry still NOT_STARTED because - // the dispatch phase ran before the slots were cleared this turn. - ret = assetUpdate(); - assert_true(errorIsOk(ret)); - assert_int_equal(entries[ASSET_LOADING_COUNT_MAX]->state, ASSET_ENTRY_STATE_NOT_STARTED); - - // Lock overflow entry so it stays LOADED after update 3. - assetEntryLock(entries[ASSET_LOADING_COUNT_MAX]); - - // Update 3: now a slot is available; the overflow entry is dispatched and loaded. + // Update 2: the slots freed during update 1 are now available, so the + // overflow entry is dispatched and loaded in this pass. ret = assetUpdate(); assert_true(errorIsOk(ret)); assert_int_equal(entries[ASSET_LOADING_COUNT_MAX]->state, ASSET_ENTRY_STATE_LOADED); - assetEntryUnlock(entries[ASSET_LOADING_COUNT_MAX]); + for(int i = 0; i < TOTAL; i++) { + assetEntryUnlock(entries[i]); + } assert_int_equal(memoryGetAllocatedCount(), 0); } @@ -492,8 +486,8 @@ int main(void) { // assetUpdate - state machine cmocka_unit_test_setup_teardown(test_update_noop_on_empty_table, asset_setup, asset_teardown), cmocka_unit_test_setup_teardown(test_update_entry_reaches_loaded, asset_setup, asset_teardown), - cmocka_unit_test_setup_teardown(test_update_slot_occupied_after_first_update, asset_setup, asset_teardown), - cmocka_unit_test_setup_teardown(test_update_slot_cleared_after_second_update, asset_setup, asset_teardown), + cmocka_unit_test_setup_teardown(test_update_slot_cleared_after_first_update, asset_setup, asset_teardown), + cmocka_unit_test_setup_teardown(test_update_slot_stays_cleared_on_further_updates, asset_setup, asset_teardown), cmocka_unit_test_setup_teardown(test_update_four_slots_fill_independently, asset_setup, asset_teardown), cmocka_unit_test_setup_teardown(test_update_loaded_entry_not_redispatched, asset_setup, asset_teardown), cmocka_unit_test_setup_teardown(test_update_overflow_queues_entries, asset_setup, asset_teardown),