mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-06-06 18:31:03 +00:00
176 lines
5.8 KiB
C
176 lines
5.8 KiB
C
![]() |
// Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||
|
// SPDX-License-Identifier: BSD-3
|
||
|
|
||
|
#ifndef TESTCASE_H
|
||
|
#define TESTCASE_H
|
||
|
|
||
|
#include "test_detail.h"
|
||
|
#include <cyaml/cyaml.h>
|
||
|
#include <capstone/capstone.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
/// Input data for a test case.
|
||
|
typedef struct {
|
||
|
char *name;
|
||
|
uint8_t *bytes; // mandatory
|
||
|
uint32_t bytes_count; // Filled by cyaml
|
||
|
char *arch; // mandatory
|
||
|
uint64_t address;
|
||
|
char **options; // mandatory
|
||
|
uint32_t options_count; // Filled by cyaml
|
||
|
} TestInput;
|
||
|
|
||
|
TestInput *test_input_new();
|
||
|
void test_input_free(TestInput *test_input);
|
||
|
TestInput *test_input_clone(TestInput *test_input);
|
||
|
char *test_input_stringify(const TestInput *test_input, const char *postfix);
|
||
|
cs_arch test_input_get_cs_arch(const TestInput *test_input);
|
||
|
cs_mode test_input_get_cs_mode(const TestInput *test_input);
|
||
|
void test_input_get_cs_option(const TestInput *test_input, cs_opt_type *otype,
|
||
|
cs_opt_value *oval);
|
||
|
|
||
|
/// A single byte
|
||
|
static const cyaml_schema_value_t byte_schema = {
|
||
|
CYAML_VALUE_UINT(CYAML_FLAG_DEFAULT, uint8_t),
|
||
|
};
|
||
|
|
||
|
/// A single option string
|
||
|
static const cyaml_schema_value_t option_schema = {
|
||
|
CYAML_VALUE_STRING(CYAML_FLAG_POINTER, char, 0, CYAML_UNLIMITED),
|
||
|
};
|
||
|
|
||
|
static const cyaml_schema_field_t test_input_mapping_schema[] = {
|
||
|
CYAML_FIELD_STRING_PTR("name", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, TestInput, name,
|
||
|
0, CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_SEQUENCE("bytes", CYAML_FLAG_POINTER, TestInput, bytes,
|
||
|
&byte_schema, 0, CYAML_UNLIMITED), // 0-MAX bytes
|
||
|
CYAML_FIELD_STRING_PTR("arch", CYAML_FLAG_POINTER, TestInput, arch, 0,
|
||
|
CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_UINT("address",
|
||
|
CYAML_FLAG_SCALAR_PLAIN | CYAML_FLAG_OPTIONAL,
|
||
|
TestInput, address),
|
||
|
CYAML_FIELD_SEQUENCE("options", CYAML_FLAG_POINTER, TestInput, options,
|
||
|
&option_schema, 0,
|
||
|
CYAML_UNLIMITED), // 0-MAX options
|
||
|
CYAML_FIELD_END
|
||
|
};
|
||
|
|
||
|
/// Data compared to the produced cs_insn.
|
||
|
typedef struct {
|
||
|
uint32_t id;
|
||
|
char *asm_text; // mandatory
|
||
|
char *op_str;
|
||
|
int32_t is_alias; ///< 0 == not given, >0 == true, <0 == false
|
||
|
uint64_t alias_id;
|
||
|
char *mnemonic;
|
||
|
TestDetail *details;
|
||
|
} TestInsnData;
|
||
|
|
||
|
TestInsnData *test_insn_data_new();
|
||
|
void test_insn_data_free(TestInsnData *test_insn_data);
|
||
|
TestInsnData *test_insn_data_clone(TestInsnData *test_insn_data);
|
||
|
|
||
|
static const cyaml_schema_field_t test_insn_data_mapping_schema[] = {
|
||
|
CYAML_FIELD_UINT("id", CYAML_FLAG_SCALAR_PLAIN | CYAML_FLAG_OPTIONAL,
|
||
|
TestInsnData, id),
|
||
|
CYAML_FIELD_STRING_PTR("asm_text", CYAML_FLAG_POINTER, TestInsnData,
|
||
|
asm_text, 0, CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_STRING_PTR(
|
||
|
"op_str", CYAML_FLAG_POINTER_NULL_STR | CYAML_FLAG_OPTIONAL,
|
||
|
TestInsnData, op_str, 0, CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_UINT("is_alias", CYAML_FLAG_OPTIONAL, TestInsnData,
|
||
|
is_alias),
|
||
|
CYAML_FIELD_INT("alias_id",
|
||
|
CYAML_FLAG_SCALAR_PLAIN | CYAML_FLAG_OPTIONAL,
|
||
|
TestInsnData, alias_id),
|
||
|
CYAML_FIELD_STRING_PTR(
|
||
|
"mnemonic", CYAML_FLAG_POINTER_NULL_STR | CYAML_FLAG_OPTIONAL,
|
||
|
TestInsnData, mnemonic, 0, CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_MAPPING_PTR(
|
||
|
"details", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
|
||
|
TestInsnData, details, test_detail_mapping_schema),
|
||
|
CYAML_FIELD_END
|
||
|
};
|
||
|
|
||
|
/// The expected data for a test. This can hold multiple instructions
|
||
|
/// if enough bytes were given.
|
||
|
typedef struct {
|
||
|
TestInsnData **insns; ///< Zero to N disassembled instructions.
|
||
|
uint32_t insns_count; ///< Filled by cyaml.
|
||
|
} TestExpected;
|
||
|
|
||
|
TestExpected *test_expected_new();
|
||
|
void test_expected_free(TestExpected *test_expected);
|
||
|
TestExpected *test_expected_clone(TestExpected *test_expected);
|
||
|
void test_expected_compare(csh *handle, TestExpected *expected, cs_insn *insns,
|
||
|
size_t insns_count, size_t arch_bits);
|
||
|
|
||
|
static const cyaml_schema_value_t insn_schema = {
|
||
|
CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, TestInsnData,
|
||
|
test_insn_data_mapping_schema),
|
||
|
};
|
||
|
|
||
|
static const cyaml_schema_field_t test_expected_mapping_schema[] = {
|
||
|
CYAML_FIELD_SEQUENCE("insns", CYAML_FLAG_POINTER, TestExpected, insns,
|
||
|
&insn_schema, 0, CYAML_UNLIMITED), // 0-MAX options
|
||
|
CYAML_FIELD_END
|
||
|
};
|
||
|
|
||
|
/// A single test case.
|
||
|
typedef struct {
|
||
|
TestInput *input; ///< Input data for a test case
|
||
|
TestExpected *expected; ///< Expected data of the test case.
|
||
|
bool skip; ///< If set, the test is skipped
|
||
|
char *skip_reason; ///< Reason this test is skipped.
|
||
|
} TestCase;
|
||
|
|
||
|
TestCase *test_case_new();
|
||
|
void test_case_free(TestCase *test_case);
|
||
|
TestCase *test_case_clone(TestCase *test_case);
|
||
|
|
||
|
static const cyaml_schema_field_t test_case_mapping_schema[] = {
|
||
|
CYAML_FIELD_MAPPING_PTR("input", CYAML_FLAG_POINTER, TestCase, input,
|
||
|
test_input_mapping_schema),
|
||
|
CYAML_FIELD_MAPPING_PTR("expected", CYAML_FLAG_POINTER, TestCase,
|
||
|
expected, test_expected_mapping_schema),
|
||
|
CYAML_FIELD_BOOL("skip", CYAML_FLAG_OPTIONAL, TestCase, skip),
|
||
|
CYAML_FIELD_STRING_PTR("skip_reason",
|
||
|
CYAML_FLAG_POINTER_NULL_STR |
|
||
|
CYAML_FLAG_OPTIONAL,
|
||
|
TestCase, skip_reason, 0, CYAML_UNLIMITED),
|
||
|
CYAML_FIELD_END
|
||
|
};
|
||
|
|
||
|
static const cyaml_schema_value_t test_case_schema = {
|
||
|
CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, TestCase,
|
||
|
test_case_mapping_schema),
|
||
|
};
|
||
|
|
||
|
typedef struct {
|
||
|
char *filename; ///< Filename. NOT filled by cyaml.
|
||
|
TestCase **test_cases;
|
||
|
uint32_t test_cases_count;
|
||
|
} TestFile;
|
||
|
|
||
|
TestFile *test_file_new();
|
||
|
void test_file_free(TestFile *test_file);
|
||
|
TestFile *test_file_clone(TestFile *test_file);
|
||
|
|
||
|
static const cyaml_schema_field_t test_file_mapping_schema[] = {
|
||
|
CYAML_FIELD_STRING_PTR(
|
||
|
"filename", CYAML_FLAG_OPTIONAL | CYAML_FLAG_POINTER_NULL_STR,
|
||
|
TestFile, filename, 0, 0),
|
||
|
CYAML_FIELD_SEQUENCE("test_cases", CYAML_FLAG_POINTER, TestFile,
|
||
|
test_cases, &test_case_schema, 1,
|
||
|
CYAML_UNLIMITED), // 1-MAX options
|
||
|
CYAML_FIELD_END
|
||
|
};
|
||
|
|
||
|
static const cyaml_schema_value_t test_file_schema = {
|
||
|
CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, TestFile,
|
||
|
test_file_mapping_schema),
|
||
|
};
|
||
|
|
||
|
#endif // TESTCASE_H
|