Skip to content

Commit

Permalink
Add tests and CI
Browse files Browse the repository at this point in the history
Using AppVeyor as CI service.

Closes #3
  • Loading branch information
Makman2 committed Jan 7, 2018
1 parent 35812f3 commit 49e79c7
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
13 changes: 13 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
environment:
matrix:
- PYTHON: "C:\\Python34"

install:
- set PATH=%PYTHON%;%PATH%
- python --version
- python -m pip install -r test-requirements.txt

build: false # Not a C# project.

test_script:
- python -m pytest
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest
5 changes: 5 additions & 0 deletions tests/native/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 2.6)

project(test-exe C)

add_executable(${PROJECT_NAME} main.c)
31 changes: 31 additions & 0 deletions tests/native/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdio.h>

void main() {
char char_value = 55;
short short_value = 12041;
int int_value = -988324;
unsigned int uint_value = 2134;

float float_value = 28.75f;
double double_value = -4.125;

char bytes[] = {11, 22, 33, 44, 55, 66, 77, 88, 99};

printf("char: %i at %p\n", char_value, &char_value);
printf("short: %i at %p\n", short_value, &short_value);
printf("int: %i at %p\n", int_value, &int_value);
printf("unsigned int: %i at %p\n", uint_value, &uint_value);

printf("float: %f at %p\n", float_value, &float_value);
printf("double: %f at %p\n", double_value, &double_value);

printf("bytes: ");
for (int i = 0; i < sizeof(bytes); i++) {
printf("%i ", bytes[i]);
}
printf("at %p\n", bytes);

puts("Press ENTER to quit...");
fflush(stdout);
getchar();
}
150 changes: 150 additions & 0 deletions tests/test_MemoryView.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from collections import namedtuple
import os
import re
from subprocess import check_call, PIPE, Popen

import pytest

from memaccess import MemoryView


TestProcessInfo = namedtuple('TestProcess', ('pid', 'lines'))


def compile_testapp():
test_app_path = os.path.join(os.getcwd(), 'tests', 'native')
build_directory = os.path.join(os.getcwd(), 'tests', 'native', 'build')

# Create necessary build directories.
os.makedirs(build_directory, exist_ok=True)

# Compile.
check_call(('cmake', test_app_path), cwd=build_directory)
check_call(('cmake', '--build', build_directory), cwd=build_directory)

return os.path.join(build_directory, 'Debug', 'test-exe')


@pytest.fixture(scope='module')
def testprocess():
test_app_path = compile_testapp()

test_process = Popen(test_app_path,
universal_newlines=True, stdin=PIPE, stdout=PIPE)

lines = []
while True:
line = test_process.stdout.readline()

if line == 'Press ENTER to quit...\n':
break

lines.append(line)

yield TestProcessInfo(pid=test_process.pid, lines=tuple(lines))

test_process.stdin.write('\n')
test_process.stdin.flush()

test_process.wait()


def match_list(rgx, lst):
for line in lst:
match = re.match(rgx, line)
if match is not None:
return match


def test_invalid_process():
# Trying to use process 0 raises an error according to API specs.
with pytest.raises(RuntimeError) as ex:
MemoryView(0)

assert str(ex.value) == "Can't open process with pid 0, error code 87"


def test_double_close(testprocess):
# Double closing is invalid.
expected_message = "Can't close process handle, error code 6"

view = MemoryView(testprocess.pid)
view.close()
with pytest.raises(RuntimeError) as ex:
view.close()

assert str(ex.value) == expected_message

# Same should happen when using context manager variant.
with MemoryView(testprocess.pid) as view:
pass
with pytest.raises(RuntimeError) as ex:
view.close()

assert str(ex.value) == expected_message


def test_read_int(testprocess):
rgx = r'int: (-?\d+) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

value = int(match.group(1))
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read_int(address) == value


def test_read_unsigned_int(testprocess):
rgx = r'unsigned int: (\d+) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

value = int(match.group(1))
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read_unsigned_int(address) == value


def test_read_char(testprocess):
rgx = r'char: (\d+) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

value = bytes([int(match.group(1))])
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read_char(address) == value


def test_read_float(testprocess):
rgx = r'float: (-?\d+(?:\.\d+)?) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

value = float(match.group(1))
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read_float(address) == value


def test_read_double(testprocess):
rgx = r'double: (-?\d+(?:\.\d+)?) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

value = float(match.group(1))
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read_double(address) == value


def test_read(testprocess):
rgx = r'bytes: (\d+(?: \d+)*) at ((?:0x)?[0-9A-Fa-f]+)'
match = match_list(rgx, testprocess.lines)

values = bytes([int(num) for num in match.group(1).split()])
address = int(match.group(2), 16)

with MemoryView(testprocess.pid) as view:
assert view.read(len(values), address) == values

0 comments on commit 49e79c7

Please sign in to comment.