mirror of
https://github.com/JesseTG/melonds-ds.git
synced 2024-11-26 16:20:48 +00:00
Add some extra tests for cheats
- Ensure they're persisted across resets - Test that they're not applied if invalid - Test that they're cleared when we ask them to be cleared
This commit is contained in:
parent
e9b376957a
commit
797d1ae324
@ -231,6 +231,8 @@ void MelonDsDs::CoreState::Reset() {
|
||||
memcpy(gbaSram.data(), Console->GetGBASave(), Console->GetGBASaveLength());
|
||||
}
|
||||
|
||||
std::vector<melonDS::ARCode> cheats = std::move(Console->AREngine.Cheats);
|
||||
|
||||
Console = nullptr;
|
||||
melonDS::NDS::Current = nullptr;
|
||||
Console = CreateConsole(
|
||||
@ -250,6 +252,8 @@ void MelonDsDs::CoreState::Reset() {
|
||||
Console->SetGBASave(gbaSram.data(), gbaSram.size());
|
||||
}
|
||||
|
||||
Console->AREngine.Cheats = std::move(cheats);
|
||||
|
||||
_ndsSramInstalled = false;
|
||||
InitFlushFirmwareTask();
|
||||
|
||||
|
@ -182,6 +182,15 @@ extern "C" bool melondsds_is_software_renderer() {
|
||||
return mode && *mode == RenderMode::Software;
|
||||
}
|
||||
|
||||
extern "C" unsigned melondsds_num_cheats() {
|
||||
using namespace MelonDsDs;
|
||||
const auto *console = Core.GetConsole();
|
||||
if (!console)
|
||||
return 0;
|
||||
|
||||
return console->AREngine.Cheats.size();
|
||||
}
|
||||
|
||||
extern "C" retro_proc_address_t MelonDsDs::GetRetroProcAddress(const char* sym) noexcept {
|
||||
if (string_is_equal(sym, "libretropy_add_integers"))
|
||||
return reinterpret_cast<retro_proc_address_t>(libretropy_add_integers);
|
||||
@ -252,6 +261,9 @@ extern "C" retro_proc_address_t MelonDsDs::GetRetroProcAddress(const char* sym)
|
||||
if (string_is_equal(sym, "melondsds_is_software_renderer"))
|
||||
return reinterpret_cast<retro_proc_address_t>(melondsds_is_software_renderer);
|
||||
|
||||
if (string_is_equal(sym, "melondsds_num_cheats"))
|
||||
return reinterpret_cast<retro_proc_address_t>(melondsds_num_cheats);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -289,6 +289,7 @@ set(MICRECORD_NDS "${CMAKE_CURRENT_SOURCE_DIR}/nds/micrecord.nds")
|
||||
|
||||
include(cmake/Basics.cmake)
|
||||
include(cmake/Booting.cmake)
|
||||
include(cmake/Cheats.cmake)
|
||||
include(cmake/Errors.cmake)
|
||||
include(cmake/Firmware.cmake)
|
||||
include(cmake/Reset.cmake)
|
||||
|
47
test/cmake/Cheats.cmake
Normal file
47
test/cmake/Cheats.cmake
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
add_python_test(
|
||||
NAME "Cheats persist after retro_reset"
|
||||
TEST_MODULE cheats.persist_after_reset
|
||||
CONTENT "${NDS_ROM}"
|
||||
)
|
||||
|
||||
add_python_test(
|
||||
NAME "Resetting cheats clears them"
|
||||
TEST_MODULE cheats.cleared_on_cheat_reset
|
||||
CONTENT "${NDS_ROM}"
|
||||
)
|
||||
|
||||
add_python_test(
|
||||
NAME "Cheats can be updated individually"
|
||||
TEST_MODULE cheats.can_be_updated_individually
|
||||
CONTENT "${NDS_ROM}"
|
||||
DISABLED
|
||||
)
|
||||
|
||||
|
||||
add_python_test(
|
||||
NAME "Cheats can be disabled individually"
|
||||
TEST_MODULE cheats.can_be_disabled_individually
|
||||
CONTENT "${NDS_ROM}"
|
||||
DISABLED
|
||||
)
|
||||
|
||||
add_python_test(
|
||||
NAME "Cheats can be toggled on the error screen"
|
||||
TEST_MODULE cheats.can_be_toggled_on_error_screen
|
||||
CONTENT "${NDS_ROM}"
|
||||
DISABLED
|
||||
)
|
||||
|
||||
add_python_test(
|
||||
NAME "Invalid cheats are not enabled"
|
||||
TEST_MODULE cheats.not_enabled_if_invalid
|
||||
CONTENT "${NDS_ROM}"
|
||||
)
|
||||
|
||||
add_python_test(
|
||||
NAME "Cheats can be disabled if they're invalid"
|
||||
TEST_MODULE cheats.can_be_disabled_if_invalid
|
||||
CONTENT "${NDS_ROM}"
|
||||
DISABLED
|
||||
)
|
0
test/python/cheats/__init__.py
Normal file
0
test/python/cheats/__init__.py
Normal file
27
test/python/cheats/cleared_on_cheat_reset.py
Normal file
27
test/python/cheats/cleared_on_cheat_reset.py
Normal file
@ -0,0 +1,27 @@
|
||||
from ctypes import CFUNCTYPE, c_uint
|
||||
|
||||
from libretro import Session
|
||||
from libretro.h import RETRO_MEMORY_SYSTEM_RAM
|
||||
|
||||
import prelude
|
||||
|
||||
session: Session
|
||||
with prelude.session() as session:
|
||||
memory = session.core.get_memory(RETRO_MEMORY_SYSTEM_RAM)
|
||||
|
||||
assert memory is not None
|
||||
|
||||
num_cheats = session.get_proc_address(b"melondsds_num_cheats", CFUNCTYPE(c_uint))
|
||||
|
||||
session.core.cheat_set(0, True, b'02000000 DEADBEEF')
|
||||
|
||||
cheats = num_cheats()
|
||||
assert cheats == 1, f"Expected 1 cheat, got {cheats}"
|
||||
|
||||
for i in range(60):
|
||||
session.run()
|
||||
|
||||
session.core.cheat_reset()
|
||||
|
||||
cheats = num_cheats()
|
||||
assert cheats == 0, f"Expected 0 cheats, got {cheats}"
|
12
test/python/cheats/not_enabled_if_invalid.py
Normal file
12
test/python/cheats/not_enabled_if_invalid.py
Normal file
@ -0,0 +1,12 @@
|
||||
from typing import cast
|
||||
|
||||
from libretro import Session, LoggerMessageInterface, LogLevel
|
||||
|
||||
import prelude
|
||||
|
||||
session: Session
|
||||
with prelude.session() as session:
|
||||
message = cast(LoggerMessageInterface, session.message)
|
||||
session.core.cheat_set(0, True, b'fgsfds')
|
||||
|
||||
assert message.message_exts[-1].level == LogLevel.WARNING
|
38
test/python/cheats/persist_after_reset.py
Normal file
38
test/python/cheats/persist_after_reset.py
Normal file
@ -0,0 +1,38 @@
|
||||
from ctypes import CFUNCTYPE, c_uint
|
||||
|
||||
from libretro import Session
|
||||
from libretro.h import RETRO_MEMORY_SYSTEM_RAM
|
||||
|
||||
import prelude
|
||||
|
||||
session: Session
|
||||
with prelude.session() as session:
|
||||
memory = session.core.get_memory(RETRO_MEMORY_SYSTEM_RAM)
|
||||
|
||||
assert memory is not None
|
||||
|
||||
num_cheats = session.get_proc_address(b"melondsds_num_cheats", CFUNCTYPE(c_uint))
|
||||
|
||||
session.core.cheat_set(0, True, b'02000000 DEADBEEF')
|
||||
# A trivial cheat code with one instruction: 0XXXXXXX-YYYYYYYY,
|
||||
# where XXXXXXX (in this case, 02000000) is the address to write to
|
||||
# and YYYYYYYY (in this case, DEADBEEF) is the value to write.
|
||||
# See https://mgba-emu.github.io/gbatek/#dscartcheatactionreplayds for more details
|
||||
|
||||
# Slicing reads the bytes in sequence, not as a word
|
||||
assert memory[0:4].tobytes() != b'\xef\xbe\xad\xde'
|
||||
|
||||
# Cheats aren't applied immediately, they're applied when the ARM7 processes a VBlank IRQ
|
||||
# (so we need to run a few frames)
|
||||
for i in range(60):
|
||||
session.run()
|
||||
|
||||
session.reset()
|
||||
|
||||
num_cheats = num_cheats()
|
||||
assert num_cheats == 1, f"Expected 1 cheat, got {num_cheats}"
|
||||
|
||||
for i in range(60):
|
||||
session.run()
|
||||
|
||||
assert memory[0:4].tobytes() == b'\xef\xbe\xad\xde', f"Expected 0xDEADBEEF, got {memory[0:4].tobytes()}"
|
Loading…
Reference in New Issue
Block a user