Skip to content

Commit

Permalink
WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
Arignir committed Dec 17, 2023
1 parent 38d2965 commit 0dfeb43
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 8 deletions.
74 changes: 74 additions & 0 deletions .github/workflows/accuracy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Accuracy

on: [push, pull_request, workflow_dispatch]

jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y meson ninja-build libsdl2-dev libglew-dev libgtk-3-dev libreadline-dev libedit-dev libcapstone-dev
- name: Build Hades w/ Debugger
run: |
meson build --werror -Dwith_debugger=true
cd build
ninja
- name: Extract BIOS
run: |
echo "$BIOS_DATA" | base64 -d | gpg --pinentry-mode loopback --passphrase "$BIOS_KEY" -d -o ./bios.bin
env:
BIOS_DATA: ${{ secrets.BIOS_DATA }}
BIOS_KEY: ${{ secrets.BIOS_KEY }}
- name: Download Test Roms
run: |
mkdir roms
cd roms
wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/arm/arm.gba
wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/thumb/thumb.gba
- name: Check Accuracy
run: |
# Setup a fake audio environment
export SDL_AUDIODRIVER=disk
ln -s /dev/null sdlaudio.raw
# Setup a fake X11 environment
export DISPLAY=:99
sudo Xvfb -ac "$DISPLAY" -screen 0 1280x1024x24 > /dev/null 2>&1 &
# Setup the configuration
cat << EOF > config.json
{
"file": {
"bios": "./bios.bin"
},
"emulation": {
"skip_bios": true,
"speed": 0,
"unbounded": false,
"backup_storage": {
"autodetect": true,
"type": 0
},
"rtc": {
"autodetect": true,
"enabled": true
}
},
}
EOF
# Run accuracy checks
python3 ./tests/run.py --binary ./build/hades --roms ./roms/
- name: Cleanup
if: always()
run: |
if [[ -f ./bios.bin ]]; then
shred -u ./bios.bin
fi
12 changes: 6 additions & 6 deletions .github/workflows/main.yml β†’ .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:
run:
shell: msys2 {0}
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
uses: msys2/setup-msys2@v2
with:
Expand All @@ -35,10 +35,10 @@ jobs:
mac-os:
runs-on: macos-latest
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
run: |
brew install meson ninja sdl2 glew create-dmg
Expand Down Expand Up @@ -130,10 +130,10 @@ jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: 'Sync source code'
- name: Fetch Source Code
uses: actions/checkout@v4
with:
submodules: 'recursive'
submodules: recursive
- name: Install Dependencies
run: |
sudo apt-get update
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/screenshots
/build
/build.*
/build-*
/games
/demos
*.gba
*.bin
config.json
.hades-dbg.history
__pycache__

3 changes: 2 additions & 1 deletion source/dbg/lang/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ debugger_lang_lexe(
while (input[i]) {
switch (input[i]) {
case '.':
case '_':
case 'a' ... 'z':
case 'A' ... 'Z': {
/* Lexe the whole identifier */
struct token *t;
size_t j;

j = 0;
while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '/') {
while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '_' || input[i + j] == '/') {
++j;
}

Expand Down
2 changes: 1 addition & 1 deletion source/gui/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ gui_config_load(

if (mjson_get_number(data, data_len, "$.emulation.speed", &d)) {
app->emulation.speed = (int)d;
app->emulation.speed = max(1, min(app->emulation.speed, 5));
app->emulation.speed = max(0, min(app->emulation.speed, 5));
}

if (mjson_get_bool(data, data_len, "$.emulation.backup_storage.autodetect", &b)) {
Expand Down
Empty file added tests/__init__.py
Empty file.
Binary file added tests/expected/ags_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/expected/arm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/expected/thumb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 126 additions & 0 deletions tests/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env python3

import os
import shutil
import filecmp
import textwrap
import argparse
import subprocess
from enum import Enum
from pathlib import Path


GREEN = '\033[32m'
YELLOW = '\033[33m'
RED = '\033[31m'
BOLD = '\033[1m'
RESET = '\033[0m'


class TestResult(Enum):
PASS = 0
SKIP = 1
FAIL = 2


class Test():
def __init__(self, name: str, rom: str, code: str, screenshot: str, skip: bool = False):
self.name = name

self.rom = rom
self.code = textwrap.dedent(code)
self.screenshot = screenshot
self.skip = skip

def run(self, hades_path: Path, rom_directory: Path, tests_screenshots_directory: Path, verbose: bool):
module_path = Path(os.path.realpath(__file__)).parent

subprocess.run(
[hades_path, rom_directory / self.rom],
input=self.code,
stdout=None if verbose else subprocess.DEVNULL,
stderr=None if verbose else subprocess.DEVNULL,
text=True,
encoding='utf-8',
check=True,
)

if not filecmp.cmp(tests_screenshots_directory / self.screenshot, module_path / 'expected' / self.screenshot, shallow=False):
raise RuntimeError("The screenshot taken during the test doesn't match the expected one.")


def main():
from suite import TESTS_SUITE

exit_code = 0

parser = argparse.ArgumentParser(
prog='Hades Accuracy Checker',
description='Tests the accuracy of Hades, a Gameboy Advance Emulator',
)

parser.add_argument(
'--binary',
nargs='?',
default='./hades',
help="Path to Hades' binary",
)

parser.add_argument(
'--roms',
nargs='?',
default='./roms',
help="Path to the test ROMS folder",
)

parser.add_argument(
'--verbose',
'-v',
action='store_true',
help="Show subcommands output",
)

args = parser.parse_args()

hades_binary = Path(os.getcwd()) / args.binary
rom_directory = Path(os.getcwd()) / args.roms

tests_screenshots_directory = Path(os.getcwd()) / 'tests_screenshots'
if tests_screenshots_directory.exists():
shutil.rmtree(tests_screenshots_directory)
os.mkdir(tests_screenshots_directory)

print(f"┏━{'━' * 30}━┳━━━━━━┓")
print(f"┃ {'Name':30s} ┃ Res. ┃")
print(f"┣━{'━' * 30}━╋━━━━━━┫")

for test in TESTS_SUITE:
result = TestResult.FAIL

try:
if test.skip:
result = TestResult.SKIP
continue

test.run(hades_binary, rom_directory, tests_screenshots_directory, args.verbose)
result = TestResult.PASS
except Exception:
result = TestResult.FAIL
finally:
if result == TestResult.PASS:
pretty_result = f'{BOLD}{GREEN}PASS{RESET}'
elif result == TestResult.SKIP:
pretty_result = f'{BOLD}{YELLOW}SKIP{RESET}'
else:
pretty_result = f'{BOLD}{RED}FAIL{RESET}'
exit_code = 1

print(f"┃ {test.name:30s} ┃ {pretty_result} ┃")

print(f"┗━{'━' * 30}━┻━━━━━━┛")

exit(exit_code)


if __name__ == '__main__':
main()
32 changes: 32 additions & 0 deletions tests/suite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from typing import List
from run import Test

TESTS_SUITE: List[Test] = [
Test(
name="Arm.gba",
rom='arm.gba',
code='''
frame 10
screenshot ./tests_screenshots/arm.png
''',
screenshot='arm.png',
),
Test(
name="Thumb.gba",
rom='thumb.gba',
code='''
frame 10
screenshot ./tests_screenshots/thumb.png
''',
screenshot='thumb.png',
),
Test(
name="AGS - Aging Tests",
rom='ags.gba',
code='''
frame 425
screenshot ./tests_screenshots/ags_01.png
''',
screenshot='ags_01.png',
)
]

0 comments on commit 0dfeb43

Please sign in to comment.