[Decompiler] Begin expression conversion, rearrange tests (#209)

* refactor tests and analysis passes

* identity test working

* combine test categories with only a few cases

* more fixes
This commit is contained in:
water111
2021-01-23 16:32:56 -05:00
committed by GitHub
parent 4a97e15b40
commit 27f0a7ca44
95 changed files with 1192 additions and 1120 deletions
+3 -1
View File
@@ -18,8 +18,10 @@ add_executable(goalc-test
test_pretty_print.cpp
test_zydis.cpp
goalc/test_goal_kernel.cpp
decompiler/FormRegressionTest.cpp
decompiler/test_AtomicOpBuilder.cpp
decompiler/test_FormRegression.cpp
decompiler/test_FormBeforeExpressions.cpp
decompiler/test_FormExpressionBuild.cpp
decompiler/test_InstructionParser.cpp
${GOALC_TEST_FRAMEWORK_SOURCES}
${GOALC_TEST_CASES})
+158
View File
@@ -0,0 +1,158 @@
#include "FormRegressionTest.h"
#include "decompiler/analysis/variable_naming.h"
#include "decompiler/analysis/reg_usage.h"
#include "decompiler/analysis/cfg_builder.h"
#include "decompiler/analysis/expression_build.h"
#include "common/goos/PrettyPrinter.h"
using namespace decompiler;
void FormRegressionTest::SetUpTestCase() {
parser = std::make_unique<InstructionParser>();
dts = std::make_unique<DecompilerTypeSystem>();
dts->parse_type_defs({"decompiler", "config", "all-types.gc"});
}
void FormRegressionTest::TearDownTestCase() {
parser.reset();
dts.reset();
parser.reset();
}
void FormRegressionTest::TestData::add_string_at_label(const std::string& label_name,
const std::string& data) {
// first, align segment 1:
while (file.words_by_seg.at(1).size() % 4) {
file.words_by_seg.at(1).push_back(LinkedWord(0));
}
// add string type tag:
LinkedWord type_tag(0);
type_tag.kind = LinkedWord::Kind::TYPE_PTR;
type_tag.symbol_name = "string";
file.words_by_seg.at(1).push_back(type_tag);
int string_start = 4 * int(file.words_by_seg.at(1).size());
// add size
file.words_by_seg.at(1).push_back(LinkedWord(int(data.length())));
// add string:
std::vector<char> bytes;
bytes.resize(((data.size() + 1 + 3) / 4) * 4);
for (size_t i = 0; i < data.size(); i++) {
bytes[i] = data[i];
}
for (size_t i = 0; i < bytes.size() / 4; i++) {
auto word = ((uint32_t*)bytes.data())[i];
file.words_by_seg.at(1).push_back(LinkedWord(word));
}
for (int i = 0; i < 3; i++) {
file.words_by_seg.at(1).push_back(LinkedWord(0));
}
// will be already null terminated.
for (auto& label : file.labels) {
if (label.name == label_name) {
label.target_segment = 1;
label.offset = string_start;
return;
}
}
EXPECT_TRUE(false);
}
std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
const std::string& code,
const TypeSpec& function_type,
bool do_expressions,
bool allow_pairs,
const std::string& method_name,
const std::vector<std::pair<std::string, std::string>>& strings) {
dts->type_prop_settings.locked = true;
dts->type_prop_settings.reset();
dts->type_prop_settings.allow_pair = allow_pairs;
dts->type_prop_settings.current_method_type = method_name;
auto program = parser->parse_program(code);
// printf("prg:\n%s\n\n", program.print().c_str());
auto test = std::make_unique<TestData>(program.instructions.size());
test->file.words_by_seg.resize(3);
test->file.labels = program.labels;
test->func.ir2.env.file = &test->file;
test->func.instructions = program.instructions;
test->func.guessed_name.set_as_global("test-function");
test->func.type = function_type;
for (auto& str : strings) {
test->add_string_at_label(str.first, str.second);
}
test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func);
test->func.analyze_prologue(test->file);
test->func.cfg = build_cfg(test->file, 0, test->func);
EXPECT_TRUE(test->func.cfg->is_fully_resolved());
auto ops = convert_function_to_atomic_ops(test->func, program.labels);
test->func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
test->func.ir2.atomic_ops_succeeded = true;
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {}));
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(),
*test->func.ir2.atomic_ops, *dts);
if (result.has_value()) {
test->func.ir2.env.set_local_vars(*result);
} else {
EXPECT_TRUE(false);
}
build_initial_forms(test->func);
EXPECT_TRUE(test->func.ir2.top_form);
// for now, just test that this can at least be called.
VariableSet vars;
test->func.ir2.top_form->collect_vars(vars);
if (do_expressions) {
bool success =
convert_to_expressions(test->func.ir2.top_form, test->func.ir2.form_pool, test->func);
EXPECT_TRUE(success);
if (!success) {
return nullptr;
}
}
return test;
}
void FormRegressionTest::test(const std::string& code,
const std::string& type,
const std::string& expected,
bool do_expressions,
bool allow_pairs,
const std::string& method_name,
const std::vector<std::pair<std::string, std::string>>& strings) {
auto ts = dts->parse_type_spec(type);
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings);
ASSERT_TRUE(test);
auto expected_form =
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
auto actual_form =
pretty_print::get_pretty_printer_reader()
.read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false)
.as_pair()
->car;
if (expected_form != actual_form) {
printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(),
expected_form.print().c_str());
}
EXPECT_TRUE(expected_form == actual_form);
}
std::unique_ptr<InstructionParser> FormRegressionTest::parser;
std::unique_ptr<DecompilerTypeSystem> FormRegressionTest::dts;
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <memory>
#include "gtest/gtest.h"
#include "decompiler/Disasm/InstructionParser.h"
#include "decompiler/util/DecompilerTypeSystem.h"
#include "decompiler/Function/Function.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
class FormRegressionTest : public ::testing::Test {
protected:
static std::unique_ptr<decompiler::InstructionParser> parser;
static std::unique_ptr<decompiler::DecompilerTypeSystem> dts;
static void SetUpTestCase();
static void TearDownTestCase();
struct TestData {
explicit TestData(int instrs) : func(0, instrs) {}
decompiler::Function func;
decompiler::LinkedObjectFile file;
void add_string_at_label(const std::string& label_name, const std::string& data);
};
std::unique_ptr<TestData> make_function(
const std::string& code,
const TypeSpec& function_type,
bool do_expressions,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {});
void test(const std::string& code,
const std::string& type,
const std::string& expected,
bool do_expressions,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {});
void test_no_expr(const std::string& code,
const std::string& type,
const std::string& expected,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
test(code, type, expected, false, allow_pairs, method_name, strings);
}
void test_with_expr(const std::string& code,
const std::string& type,
const std::string& expected,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
test(code, type, expected, true, allow_pairs, method_name, strings);
}
};
+1 -1
View File
@@ -1,6 +1,6 @@
#include "gtest/gtest.h"
#include "decompiler/IR2/AtomicOp.h"
#include "decompiler/IR2/atomic_op_builder.h"
#include "decompiler/analysis/atomic_op_builder.h"
#include "decompiler/Disasm/InstructionParser.h"
#include "third-party/fmt/core.h"
#include "third-party/fmt/format.h"
@@ -1,162 +1,9 @@
#include <memory>
#include "gtest/gtest.h"
#include "decompiler/Disasm/InstructionParser.h"
#include "decompiler/Disasm/DecompilerLabel.h"
#include "decompiler/Function/Function.h"
#include "decompiler/ObjectFile/ObjectFileDB.h"
#include "decompiler/IR2/variable_naming.h"
#include "decompiler/IR2/cfg_builder.h"
#include "common/goos/PrettyPrinter.h"
#include "FormRegressionTest.h"
using namespace decompiler;
class DecompilerRegressionTest : public ::testing::Test {
protected:
static std::unique_ptr<InstructionParser> parser;
static std::unique_ptr<DecompilerTypeSystem> dts;
static void SetUpTestCase() {
parser = std::make_unique<InstructionParser>();
dts = std::make_unique<DecompilerTypeSystem>();
dts->parse_type_defs({"decompiler", "config", "all-types.gc"});
}
static void TearDownTestCase() {
parser.reset();
dts.reset();
parser.reset();
}
struct TestData {
explicit TestData(int instrs) : func(0, instrs) {}
Function func;
LinkedObjectFile file;
void add_string_at_label(const std::string& label_name, const std::string& data) {
// first, align segment 1:
while (file.words_by_seg.at(1).size() % 4) {
file.words_by_seg.at(1).push_back(LinkedWord(0));
}
// add string type tag:
LinkedWord type_tag(0);
type_tag.kind = LinkedWord::Kind::TYPE_PTR;
type_tag.symbol_name = "string";
file.words_by_seg.at(1).push_back(type_tag);
int string_start = 4 * int(file.words_by_seg.at(1).size());
// add size
file.words_by_seg.at(1).push_back(LinkedWord(int(data.length())));
// add string:
std::vector<char> bytes;
bytes.resize(((data.size() + 1 + 3) / 4) * 4);
for (size_t i = 0; i < data.size(); i++) {
bytes[i] = data[i];
}
for (size_t i = 0; i < bytes.size() / 4; i++) {
auto word = ((uint32_t*)bytes.data())[i];
file.words_by_seg.at(1).push_back(LinkedWord(word));
}
for (int i = 0; i < 3; i++) {
file.words_by_seg.at(1).push_back(LinkedWord(0));
}
// will be already null terminated.
for (auto& label : file.labels) {
if (label.name == label_name) {
label.target_segment = 1;
label.offset = string_start;
return;
}
}
EXPECT_TRUE(false);
}
};
std::unique_ptr<TestData> make_function(
const std::string& code,
const TypeSpec& function_type,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
dts->type_prop_settings.locked = true;
dts->type_prop_settings.reset();
dts->type_prop_settings.allow_pair = allow_pairs;
dts->type_prop_settings.current_method_type = method_name;
auto program = parser->parse_program(code);
// printf("prg:\n%s\n\n", program.print().c_str());
auto test = std::make_unique<TestData>(program.instructions.size());
test->file.words_by_seg.resize(3);
test->file.labels = program.labels;
test->func.ir2.env.file = &test->file;
test->func.instructions = program.instructions;
test->func.guessed_name.set_as_global("test-function");
for (auto& str : strings) {
test->add_string_at_label(str.first, str.second);
}
test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func);
test->func.analyze_prologue(test->file);
test->func.cfg = build_cfg(test->file, 0, test->func);
EXPECT_TRUE(test->func.cfg->is_fully_resolved());
auto ops = convert_function_to_atomic_ops(test->func, program.labels);
test->func.ir2.atomic_ops = std::make_shared<FunctionAtomicOps>(std::move(ops));
test->func.ir2.atomic_ops_succeeded = true;
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {}));
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(),
*test->func.ir2.atomic_ops, *dts);
if (result.has_value()) {
test->func.ir2.env.set_local_vars(*result);
} else {
EXPECT_TRUE(false);
}
build_initial_forms(test->func);
EXPECT_TRUE(test->func.ir2.top_form);
// for now, just test that this can at least be called.
VariableSet vars;
test->func.ir2.top_form->collect_vars(vars);
return test;
}
void test(const std::string& code,
const std::string& type,
const std::string& expected,
bool allow_pairs = false,
const std::string& method_name = "",
const std::vector<std::pair<std::string, std::string>>& strings = {}) {
auto ts = dts->parse_type_spec(type);
auto test = make_function(code, ts, allow_pairs, method_name, strings);
auto expected_form =
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
auto actual_form =
pretty_print::get_pretty_printer_reader()
.read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false)
.as_pair()
->car;
if (expected_form != actual_form) {
printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(),
expected_form.print().c_str());
}
EXPECT_TRUE(expected_form == actual_form);
}
};
std::unique_ptr<InstructionParser> DecompilerRegressionTest::parser;
std::unique_ptr<DecompilerTypeSystem> DecompilerRegressionTest::dts;
TEST_F(DecompilerRegressionTest, StringTest) {
TEST_F(FormRegressionTest, StringTest) {
std::string func =
" sll r0, r0, 0\n"
"L100:\n"
@@ -164,7 +11,7 @@ TEST_F(DecompilerRegressionTest, StringTest) {
"L101:\n"
" jr ra\n"
" daddu sp, sp, r0";
auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, "",
auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, false, "",
{{"L100", "testing-string"}, {"L101", "testing-string-2"}});
EXPECT_EQ(test->file.get_goal_string_by_label(test->file.get_label_by_name("L100")),
@@ -173,7 +20,7 @@ TEST_F(DecompilerRegressionTest, StringTest) {
"testing-string-2");
}
TEST_F(DecompilerRegressionTest, SimplestTest) {
TEST_F(FormRegressionTest, SimplestTest) {
std::string func =
" sll r0, r0, 0\n"
" or v0, a0, r0\n"
@@ -181,10 +28,10 @@ TEST_F(DecompilerRegressionTest, SimplestTest) {
" daddu sp, sp, r0";
std::string type = "(function object object)";
std::string expected = "(set! v0-0 a0-0)";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, FloatingPointBasic) {
TEST_F(FormRegressionTest, FloatingPointBasic) {
std::string func =
" sll r0, r0, 0\n"
"L345:\n"
@@ -206,10 +53,10 @@ TEST_F(DecompilerRegressionTest, FloatingPointBasic) {
" (set! f0-1 (/.s f0-0 f1-0))\n"
" (set! v0-0 (fpr->gpr f0-1))\n"
" )";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Op3) {
TEST_F(FormRegressionTest, Op3) {
std::string func =
" sll r0, r0, 0\n"
"L308:\n"
@@ -218,10 +65,10 @@ TEST_F(DecompilerRegressionTest, Op3) {
" daddu sp, sp, r0";
std::string type = "(function int int int)";
std::string expected = "(set! v0-0 (*.si a0-0 a1-0))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Division) {
TEST_F(FormRegressionTest, Division) {
std::string func =
" sll r0, r0, 0\n"
"L307:\n"
@@ -231,10 +78,10 @@ TEST_F(DecompilerRegressionTest, Division) {
" daddu sp, sp, r0";
std::string type = "(function int int int)";
std::string expected = "(set! v0-0 (/.si a0-0 a1-0))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Ash) {
TEST_F(FormRegressionTest, Ash) {
std::string func =
" sll r0, r0, 0\n"
"L305:\n"
@@ -251,10 +98,10 @@ TEST_F(DecompilerRegressionTest, Ash) {
" sll r0, r0, 0";
std::string type = "(function int int int)";
std::string expected = "(begin (set! v1-0 a0-0) (set! v0-0 (ash.si v1-0 a1-0)))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Abs) {
TEST_F(FormRegressionTest, Abs) {
std::string func =
" sll r0, r0, 0\n"
"L301:\n"
@@ -267,10 +114,10 @@ TEST_F(DecompilerRegressionTest, Abs) {
" daddu sp, sp, r0";
std::string type = "(function int int)";
std::string expected = "(begin (set! v0-0 a0-0) (set! v0-1 (abs v0-0)))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Min) {
TEST_F(FormRegressionTest, Min) {
std::string func =
" sll r0, r0, 0\n"
" or v0, a0, r0\n"
@@ -281,10 +128,10 @@ TEST_F(DecompilerRegressionTest, Min) {
" daddu sp, sp, r0";
std::string type = "(function int int int)";
std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (min.si v0-0 v1-0)))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, Max) {
TEST_F(FormRegressionTest, Max) {
std::string func =
" sll r0, r0, 0\n"
"L299:\n"
@@ -296,10 +143,10 @@ TEST_F(DecompilerRegressionTest, Max) {
" daddu sp, sp, r0";
std::string type = "(function int int int)";
std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (max.si v0-0 v1-0)))";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, FormatString) {
TEST_F(FormRegressionTest, FormatString) {
std::string func =
" sll r0, r0, 0\n"
"L343:\n"
@@ -336,10 +183,10 @@ TEST_F(DecompilerRegressionTest, FormatString) {
" (set! v0-0 (call! a0-1 a1-0 a2-0))\n" // #t, "~f", the float
" (set! v0-1 gp-0)\n"
" )";
test(func, type, expected, false, "", {{"L343", "~f"}});
test_no_expr(func, type, expected, false, "", {{"L343", "~f"}});
}
TEST_F(DecompilerRegressionTest, WhileLoop) {
TEST_F(FormRegressionTest, WhileLoop) {
std::string func =
" sll r0, r0, 0\n"
"L285:\n"
@@ -378,11 +225,11 @@ TEST_F(DecompilerRegressionTest, WhileLoop) {
" )\n"
" (set! v0-1 '#f)\n"
" )";
test(func, type, expected);
test_no_expr(func, type, expected);
}
// Note - this test looks weird because or's aren't fully processed at this point.
TEST_F(DecompilerRegressionTest, Or) {
TEST_F(FormRegressionTest, Or) {
std::string func =
" sll r0, r0, 0\n"
"L280:\n"
@@ -443,10 +290,10 @@ TEST_F(DecompilerRegressionTest, Or) {
" )\n"
" (set! v0-1 '#f)\n"
" )";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, DynamicMethodAccess) {
TEST_F(FormRegressionTest, DynamicMethodAccess) {
std::string func =
" sll r0, r0, 0\n"
@@ -520,10 +367,10 @@ TEST_F(DecompilerRegressionTest, DynamicMethodAccess) {
" )\n"
" (set! v1-5 '#f)\n"
" )";
test(func, type, expected);
test_no_expr(func, type, expected);
}
TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) {
TEST_F(FormRegressionTest, SimpleLoopMergeCheck) {
std::string func =
" sll r0, r0, 0\n"
@@ -563,10 +410,10 @@ TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) {
" (set! v1-2 '#f)\n"
" (set! v0-0 (l.w (+ a0-0 -2)))\n"
" )";
test(func, type, expected, true);
test_no_expr(func, type, expected, true);
}
TEST_F(DecompilerRegressionTest, And) {
TEST_F(FormRegressionTest, And) {
std::string func =
" sll r0, r0, 0\n"
@@ -632,10 +479,10 @@ TEST_F(DecompilerRegressionTest, And) {
" (set! v1-2 '#f)\n" // while's false, I think.
" )\n"
" )";
test(func, type, expected, true);
test_no_expr(func, type, expected, true);
}
TEST_F(DecompilerRegressionTest, FunctionCall) {
TEST_F(FormRegressionTest, FunctionCall) {
// nmember
std::string func =
" sll r0, r0, 0\n"
@@ -715,10 +562,10 @@ TEST_F(DecompilerRegressionTest, FunctionCall) {
" )\n"
" (set! v0-2 gp-0)\n" // not empty, so return the result
" )"; // the (set! v0 #f) from the if is added later.
test(func, type, expected, true);
test_no_expr(func, type, expected, true);
}
TEST_F(DecompilerRegressionTest, NestedAndOr) {
TEST_F(FormRegressionTest, NestedAndOr) {
std::string func =
" sll r0, r0, 0\n"
@@ -886,10 +733,10 @@ TEST_F(DecompilerRegressionTest, NestedAndOr) {
" (set! v1-12 '#f)\n"
" (set! v0-1 gp-0)\n"
" )";
test(func, type, expected, true);
test_no_expr(func, type, expected, true);
}
TEST_F(DecompilerRegressionTest, NewMethod) {
TEST_F(FormRegressionTest, NewMethod) {
// inline-array-class new
std::string func =
" sll r0, r0, 0\n"
@@ -941,10 +788,10 @@ TEST_F(DecompilerRegressionTest, NewMethod) {
" (s.w! v0-0 gp-0)\n" // store size
" (s.w! (+ v0-0 4) gp-0)\n"
" )";
test(func, type, expected, false, "inline-array-class");
test_no_expr(func, type, expected, false, "inline-array-class");
}
TEST_F(DecompilerRegressionTest, Recursive) {
TEST_F(FormRegressionTest, Recursive) {
std::string func =
" sll r0, r0, 0\n"
@@ -985,10 +832,10 @@ TEST_F(DecompilerRegressionTest, Recursive) {
" (set! v0-2 (*.si gp-0 v0-1))\n" // not quite a tail call...
" )\n"
" )";
test(func, type, expected, false);
test_no_expr(func, type, expected, false);
}
TEST_F(DecompilerRegressionTest, TypeOf) {
TEST_F(FormRegressionTest, TypeOf) {
std::string func =
" sll r0, r0, 0\n"
@@ -1020,5 +867,5 @@ TEST_F(DecompilerRegressionTest, TypeOf) {
" (set! t9-0 (l.wu (+ v1-1 24)))\n" // print method.
" (set! v0-0 (call! a0-0))\n"
" )";
test(func, type, expected, false);
test_no_expr(func, type, expected, false);
}
@@ -0,0 +1,80 @@
#include "gtest/gtest.h"
#include "FormRegressionTest.h"
using namespace decompiler;
TEST_F(FormRegressionTest, ExprIdentity) {
std::string func =
" sll r0, r0, 0\n"
" or v0, a0, r0\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function object object)";
std::string expected = "a0-0";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, ExprFloatingPoint) {
std::string func =
" sll r0, r0, 0\n"
"L345:\n"
" daddiu sp, sp, -16\n"
" sd fp, 8(sp)\n"
" or fp, t9, r0\n"
" lwc1 f0, L345(fp)\n"
" mtc1 f1, a0\n"
" div.s f0, f0, f1\n"
" mfc1 v0, f0\n"
" ld fp, 8(sp)\n"
" jr ra\n"
" daddiu sp, sp, 16";
std::string type = "(function float float)";
std::string expected = "(/ (l.f L345) a0-0)";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, AdditionSigned) {
std::string func =
" sll r0, r0, 0\n"
" daddu v0, a0, a1\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function int int int)";
std::string expected = "(+ a0-0 a1-0)";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, AdditionUnSigned) {
std::string func =
" sll r0, r0, 0\n"
" daddu v0, a0, a1\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function uint uint uint)";
std::string expected = "(+ a0-0 a1-0)";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, AdditionMixed1) {
std::string func =
" sll r0, r0, 0\n"
" daddu v0, a0, a1\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function int uint int)";
std::string expected = "(+ a0-0 (the-as int a1-0))";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, AdditionMixed2) {
std::string func =
" sll r0, r0, 0\n"
" daddu v0, a0, a1\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function uint int uint)";
std::string expected = "(+ a0-0 (the-as uint a1-0))";
test_with_expr(func, type, expected);
}
// TODO - test the additions, but with the wrong return types.
-10
View File
@@ -2,15 +2,5 @@
#include "test_collections.cpp"
#include "test_compiler.cpp"
#include "test_control_statements.cpp"
#include "test_float.cpp"
#include "test_functions.cpp"
#include "test_library.cpp"
#include "test_logic.cpp"
#include "test_loop_recur.cpp"
#include "test_macros.cpp"
#include "test_methods.cpp"
#include "test_pointers.cpp"
#include "test_strings.cpp"
#include "test_symbols.cpp"
#include "test_variables.cpp"
#include "test_with_game.cpp"
+76 -33
View File
@@ -121,15 +121,21 @@ class ArithmeticTests : public testing::TestWithParam<IntegerParam> {
// Per-test-suite set-up.
// Called before the first test in this test suite.
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
compiler = std::make_unique<Compiler>();
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
}
// Per-test-suite tear-down.
// Called after the last test in this test suite.
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
compiler->shutdown_target();
runtime_thread->join();
runtime_thread.reset();
compiler.reset();
runner.reset();
}
// You can define per-test set-up logic as usual.
@@ -142,9 +148,9 @@ class ArithmeticTests : public testing::TestWithParam<IntegerParam> {
void TearDown() {}
// Common Resources Across all Tests in the Suite
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
static std::unique_ptr<std::thread> runtime_thread;
static std::unique_ptr<Compiler> compiler;
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
// Just to promote better test organization, supports nesting the test files 1 directory deep
std::string testCategory = "arithmetic";
@@ -154,9 +160,9 @@ class ArithmeticTests : public testing::TestWithParam<IntegerParam> {
// You must initialize the static variables outside of the declaration, or you'll run into
// unresolved external errors
std::thread ArithmeticTests::runtime_thread;
Compiler ArithmeticTests::compiler;
GoalTest::CompilerTestRunner ArithmeticTests::runner;
std::unique_ptr<std::thread> ArithmeticTests::runtime_thread;
std::unique_ptr<Compiler> ArithmeticTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> ArithmeticTests::runner;
// Finally, we define our generic test, given our custom class that represents our test inputs
// we can generate the lisp file, and pass along the path to the test runner
@@ -169,7 +175,7 @@ TEST_P(ArithmeticTests, EvalIntegers) {
std::string testFile = "eval-integer-" + std::to_string(param.index) + ".generated.gc";
env.write("eval-integer.template.gc", data, testFile);
runner.run_test(testCategory, testFile, {param.eval()});
runner->run_test(testCategory, testFile, {param.eval()});
}
// ValuesIn, is not the only way to use a parameterized test, but the most applicable for this
@@ -184,65 +190,102 @@ INSTANTIATE_TEST_SUITE_P(EvalIntegers,
IntegerParam(0), IntegerParam(-0)})));
TEST_F(ArithmeticTests, Addition) {
runner.run_static_test(env, testCategory, "add-int-literals.static.gc", {"13\n"});
runner.run_static_test(env, testCategory, "add-let.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "add-int-literals.static.gc", {"13\n"});
runner->run_static_test(env, testCategory, "add-let.static.gc", {"7\n"});
}
TEST_F(ArithmeticTests, AddIntegerFunction) {
runner.run_static_test(env, testCategory, "add-function.static.gc", {"21\n"});
runner->run_static_test(env, testCategory, "add-function.static.gc", {"21\n"});
}
TEST_F(ArithmeticTests, AddIntegerMultiple) {
runner.run_static_test(env, testCategory, "add-int-multiple.static.gc", {"15\n"});
runner.run_static_test(env, testCategory, "add-int-multiple-2.static.gc", {"15\n"});
runner->run_static_test(env, testCategory, "add-int-multiple.static.gc", {"15\n"});
runner->run_static_test(env, testCategory, "add-int-multiple-2.static.gc", {"15\n"});
}
TEST_F(ArithmeticTests, AddIntegerVariables) {
runner.run_static_test(env, testCategory, "add-int-vars.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "add-int-vars.static.gc", {"7\n"});
}
TEST_F(ArithmeticTests, AshFunction) {
runner.run_static_test(env, testCategory, "ash.static.gc", {"18\n"});
runner->run_static_test(env, testCategory, "ash.static.gc", {"18\n"});
}
TEST_F(ArithmeticTests, Division) {
runner.run_static_test(env, testCategory, "divide-1.static.gc", {"6\n"});
runner.run_static_test(env, testCategory, "divide-2.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "divide-1.static.gc", {"6\n"});
runner->run_static_test(env, testCategory, "divide-2.static.gc", {"7\n"});
}
TEST_F(ArithmeticTests, IntegerSymbol) {
runner.run_static_test(env, testCategory, "negative-int-symbol.static.gc", {"-123\n"});
runner->run_static_test(env, testCategory, "negative-int-symbol.static.gc", {"-123\n"});
}
TEST_F(ArithmeticTests, Modulus) {
runner.run_static_test(env, testCategory, "mod.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "mod.static.gc", {"7\n"});
}
TEST_F(ArithmeticTests, Multiplication) {
runner.run_static_test(env, testCategory, "multiply.static.gc", {"-12\n"});
runner.run_static_test(env, testCategory, "multiply-let.static.gc", {"3\n"});
runner->run_static_test(env, testCategory, "multiply.static.gc", {"-12\n"});
runner->run_static_test(env, testCategory, "multiply-let.static.gc", {"3\n"});
}
TEST_F(ArithmeticTests, NestedFunctionCall) {
runner.run_static_test(env, testCategory, "nested-function.static.gc", {"10\n"});
runner->run_static_test(env, testCategory, "nested-function.static.gc", {"10\n"});
}
TEST_F(ArithmeticTests, VariableShift) {
runner.run_static_test(env, testCategory, "shiftvs.static.gc", {"11\n"});
runner->run_static_test(env, testCategory, "shiftvs.static.gc", {"11\n"});
}
TEST_F(ArithmeticTests, FixedShift) {
// same math as the variable shift test, just using the fixed shift operators.
runner.run_static_test(env, testCategory, "shift-fixed.static.gc", {"11\n"});
runner->run_static_test(env, testCategory, "shift-fixed.static.gc", {"11\n"});
}
TEST_F(ArithmeticTests, Subtraction) {
runner.run_static_test(env, testCategory, "subtract-1.static.gc", {"4\n"});
runner.run_static_test(env, testCategory, "subtract-2.static.gc", {"4\n"});
runner.run_static_test(env, testCategory, "subtract-let.static.gc", {"3\n"});
runner->run_static_test(env, testCategory, "subtract-1.static.gc", {"4\n"});
runner->run_static_test(env, testCategory, "subtract-2.static.gc", {"4\n"});
runner->run_static_test(env, testCategory, "subtract-let.static.gc", {"3\n"});
}
TEST_F(ArithmeticTests, Multiplication2) {
runner.run_static_test(env, testCategory, "multiply32.static.gc", {"-1234478448\n"});
runner.run_static_test(env, testCategory, "multiply64.static.gc", {"93270638141856400\n"});
}
runner->run_static_test(env, testCategory, "multiply32.static.gc", {"-1234478448\n"});
runner->run_static_test(env, testCategory, "multiply64.static.gc", {"93270638141856400\n"});
}
TEST_F(ArithmeticTests, Constants) {
runner->run_static_test(env, testCategory, "float.static.gc", {"1067316150\n"});
runner->run_static_test(env, testCategory, "function-return-float-constant.static.gc",
{"3.14149\n0\n"});
}
TEST_F(ArithmeticTests, Operations) {
runner->run_static_test(env, testCategory, "float-pow.static.gc", {"256\n0\n"});
runner->run_static_test(env, testCategory, "float-product.static.gc", {"120.0000\n0\n"});
}
TEST_F(ArithmeticTests, Symbols) {
runner->run_static_test(env, testCategory, "float-in-symbol.static.gc", {"2345.6000\n0\n"});
}
TEST_F(ArithmeticTests, Functions) {
runner->run_static_test(env, testCategory, "float-function.static.gc", {"10.152\n0\n"});
runner->run_static_test(
env, testCategory, "nested-float-functions.static.gc",
{"i 1.4400 3.4000\nr 10.1523\ni 1.2000 10.1523\nr 17.5432\n17.543 10.152\n0\n"});
}
TEST_F(ArithmeticTests, MinMax) {
runner->run_static_test(env, testCategory, "float-max.static.gc", {"3.70\n0\n"});
runner->run_static_test(env, testCategory, "float-min.static.gc", {"-1.20\n0\n"});
}
TEST_F(ArithmeticTests, LogicalOperators) {
runner->run_static_test(env, testCategory, "logand.static.gc", {"4\n"});
runner->run_static_test(env, testCategory, "logior.static.gc", {"60\n"});
runner->run_static_test(env, testCategory, "logxor.static.gc", {"56\n"});
}
TEST_F(ArithmeticTests, Comparison) {
runner->run_static_test(env, testCategory, "signed-int-compare.static.gc", {"12\n"});
}
+25 -19
View File
@@ -25,13 +25,19 @@ struct CollectionParam {
class CollectionTests : public testing::TestWithParam<CollectionParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
compiler = std::make_unique<Compiler>();
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
compiler->shutdown_target();
runtime_thread->join();
runtime_thread.reset();
compiler.reset();
runner.reset();
}
void SetUp() {
@@ -41,36 +47,36 @@ class CollectionTests : public testing::TestWithParam<CollectionParam> {
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
static std::unique_ptr<std::thread> runtime_thread;
static std::unique_ptr<Compiler> compiler;
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "collections";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread CollectionTests::runtime_thread;
Compiler CollectionTests::compiler;
GoalTest::CompilerTestRunner CollectionTests::runner;
std::unique_ptr<std::thread> CollectionTests::runtime_thread;
std::unique_ptr<Compiler> CollectionTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> CollectionTests::runner;
TEST_F(CollectionTests, Pairs) {
runner.run_static_test(env, testCategory, "empty-pair.static.gc", {"()\n0\n"});
runner.run_static_test(env, testCategory, "pair-check.static.gc", {"#t#f\n0\n"});
runner->run_static_test(env, testCategory, "empty-pair.static.gc", {"()\n0\n"});
runner->run_static_test(env, testCategory, "pair-check.static.gc", {"#t#f\n0\n"});
}
TEST_F(CollectionTests, Lists) {
runner.run_static_test(env, testCategory, "list.static.gc", {"(a b c d)\n0\n"});
runner->run_static_test(env, testCategory, "list.static.gc", {"(a b c d)\n0\n"});
}
TEST_F(CollectionTests, InlineArray) {
runner.run_static_test(env, testCategory, "inline-array-field.static.gc", {"16\n"});
runner->run_static_test(env, testCategory, "inline-array-field.static.gc", {"16\n"});
}
TEST_F(CollectionTests, Operations) {
runner.run_static_test(env, testCategory, "cons.static.gc", {"(a . b)\n0\n"});
runner.run_static_test(env, testCategory, "car-cdr-get.static.gc", {"ab\n0\n"});
runner.run_static_test(env, testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"});
runner.run_static_test(env, testCategory, "nested-car-cdr-set.static.gc",
{"efgh\n((e . g) f . h)\n0\n"});
runner->run_static_test(env, testCategory, "cons.static.gc", {"(a . b)\n0\n"});
runner->run_static_test(env, testCategory, "car-cdr-get.static.gc", {"ab\n0\n"});
runner->run_static_test(env, testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"});
runner->run_static_test(env, testCategory, "nested-car-cdr-set.static.gc",
{"efgh\n((e . g) f . h)\n0\n"});
}
+141 -16
View File
@@ -25,13 +25,19 @@ struct ControlStatementParam {
class ControlStatementTests : public testing::TestWithParam<ControlStatementParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
runtime_thread = std::make_unique<std::thread>(std::thread((GoalTest::runtime_no_kernel)));
compiler = std::make_unique<Compiler>();
runner = std::make_unique<GoalTest::CompilerTestRunner>();
runner->c = compiler.get();
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
compiler->shutdown_target();
runtime_thread->join();
runtime_thread.reset();
compiler.reset();
runner.reset();
}
void SetUp() {
@@ -41,33 +47,152 @@ class ControlStatementTests : public testing::TestWithParam<ControlStatementPara
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
static std::unique_ptr<std::thread> runtime_thread;
static std::unique_ptr<Compiler> compiler;
static std::unique_ptr<GoalTest::CompilerTestRunner> runner;
std::string testCategory = "control-statements";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread ControlStatementTests::runtime_thread;
Compiler ControlStatementTests::compiler;
GoalTest::CompilerTestRunner ControlStatementTests::runner;
std::unique_ptr<std::thread> ControlStatementTests::runtime_thread;
std::unique_ptr<Compiler> ControlStatementTests::compiler;
std::unique_ptr<GoalTest::CompilerTestRunner> ControlStatementTests::runner;
TEST_F(ControlStatementTests, ConditionalCompilation) {
runner.run_static_test(env, testCategory, "conditional-compilation.static.gc", {"3\n"});
runner->run_static_test(env, testCategory, "conditional-compilation.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, Blocks) {
runner.run_static_test(env, testCategory, "nested-blocks-1.static.gc", {"7\n"});
runner.run_static_test(env, testCategory, "nested-blocks-2.static.gc", {"8\n"});
runner.run_static_test(env, testCategory, "nested-blocks-3.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "nested-blocks-1.static.gc", {"7\n"});
runner->run_static_test(env, testCategory, "nested-blocks-2.static.gc", {"8\n"});
runner->run_static_test(env, testCategory, "nested-blocks-3.static.gc", {"7\n"});
}
TEST_F(ControlStatementTests, GoTo) {
runner.run_static_test(env, testCategory, "goto.static.gc", {"3\n"});
runner->run_static_test(env, testCategory, "goto.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, Branch) {
runner.run_static_test(env, testCategory, "return-value-of-if.static.gc", {"123\n"});
runner->run_static_test(env, testCategory, "return-value-of-if.static.gc", {"123\n"});
}
TEST_F(ControlStatementTests, DoTimes) {
runner->run_static_test(env, testCategory, "dotimes.static.gc", {"4950\n"});
}
TEST_F(ControlStatementTests, Factorial) {
runner->run_static_test(env, testCategory, "factorial-recursive.static.gc", {"3628800\n"});
runner->run_static_test(env, testCategory, "factorial-iterative.static.gc", {"3628800\n"});
}
TEST_F(ControlStatementTests, Definitions) {
runner->run_static_test(env, testCategory, "defun-return-constant.static.gc", {"12\n"});
runner->run_static_test(env, testCategory, "defun-return-symbol.static.gc", {"42\n"});
}
TEST_F(ControlStatementTests, ReturnValue) {
runner->run_static_test(env, testCategory, "return.static.gc", {"77\n"});
runner->run_static_test(env, testCategory, "return-arg.static.gc", {"23\n"});
runner->run_static_test(env, testCategory, "return-colors.static.gc", {"77\n"});
}
TEST_F(ControlStatementTests, Calling) {
runner->run_static_test(env, testCategory, "nested-call.static.gc", {"2\n"});
runner->run_static_test(env, testCategory, "inline-call.static.gc", {"44\n"});
runner->run_static_test(env, testCategory, "simple-call.static.gc", {"30\n"});
}
TEST_F(ControlStatementTests, Anonymous) {
runner->run_static_test(env, testCategory, "declare-inline.static.gc", {"32\n"});
runner->run_static_test(env, testCategory, "lambda-1.static.gc", {"2\n"});
}
TEST_F(ControlStatementTests, InlineIsInline) {
auto code = compiler->get_goos().reader.read_from_file(
{"test/goalc/source_templates/control-statements/declare-inline.static.gc"});
auto compiled = compiler->compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
bool got_mult = false;
for (auto& x : ir) {
EXPECT_EQ(dynamic_cast<IR_FunctionCall*>(x.get()), nullptr);
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im) {
EXPECT_EQ(as_im->get_kind(), IntegerMathKind::IMUL_32);
got_mult = true;
}
}
EXPECT_TRUE(got_mult);
}
TEST_F(ControlStatementTests, AllowInline) {
auto code = compiler->get_goos().reader.read_from_file(
{"test/goalc/source_templates/control-statements/inline-call.static.gc"});
auto compiled = compiler->compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
int got_mult = 0;
int got_call = 0;
for (auto& x : ir) {
if (dynamic_cast<IR_FunctionCall*>(x.get())) {
got_call++;
}
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im && as_im->get_kind() == IntegerMathKind::IMUL_32) {
got_mult++;
}
}
EXPECT_EQ(got_mult, 1);
EXPECT_EQ(got_call, 1);
}
TEST_F(ControlStatementTests, ReturnNone) {
runner->run_static_test(env, testCategory, "function-returning-none.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, InlineBlock1) {
runner->run_static_test(env, testCategory, "inline-with-block-1.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, InlineBlock2) {
runner->run_static_test(env, testCategory, "inline-with-block-2.static.gc", {"3\n"});
}
TEST_F(ControlStatementTests, InlineBlock3) {
runner->run_static_test(env, testCategory, "inline-with-block-3.static.gc", {"4\n"});
}
TEST_F(ControlStatementTests, InlineBlock4) {
runner->run_static_test(env, testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"});
}
TEST_F(ControlStatementTests, ReturnFromTrick) {
runner->run_static_test(env, testCategory, "return-from-trick.static.gc", {"1\n"});
}
TEST_F(ControlStatementTests, Set) {
runner->run_static_test(env, testCategory, "set-symbol.static.gc", {"22\n"});
}
TEST_F(ControlStatementTests, Protect) {
runner->run_static_test(env, testCategory, "protect.static.gc", {"33\n"});
}
TEST_F(ControlStatementTests, Align) {
runner->run_static_test(env, testCategory, "align16-1.static.gc", {"80\n"});
runner->run_static_test(env, testCategory, "align16-2.static.gc", {"64\n"});
}
TEST_F(ControlStatementTests, Defsmacro) {
runner->run_static_test(env, testCategory, "defsmacro-defgmacro.static.gc", {"20\n"});
}
TEST_F(ControlStatementTests, Desfun) {
runner->run_static_test(env, testCategory, "desfun.static.gc", {"4\n"});
}
TEST_F(ControlStatementTests, DeReference) {
runner->run_static_test(env, testCategory, "methods.static.gc", {"#t#t\n0\n"});
}
-82
View File
@@ -1,82 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct FloatParam {
// TODO - Not Needed Yet
};
class FloatTests : public testing::TestWithParam<FloatParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "float";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread FloatTests::runtime_thread;
Compiler FloatTests::compiler;
GoalTest::CompilerTestRunner FloatTests::runner;
TEST_F(FloatTests, Constants) {
runner.run_static_test(env, testCategory, "float.static.gc", {"1067316150\n"});
runner.run_static_test(env, testCategory, "function-return-float-constant.static.gc",
{"3.14149\n0\n"});
}
TEST_F(FloatTests, Operations) {
runner.run_static_test(env, testCategory, "float-pow.static.gc", {"256\n0\n"});
runner.run_static_test(env, testCategory, "float-product.static.gc", {"120.0000\n0\n"});
}
TEST_F(FloatTests, Symbols) {
runner.run_static_test(env, testCategory, "float-in-symbol.static.gc", {"2345.6000\n0\n"});
}
TEST_F(FloatTests, Functions) {
runner.run_static_test(env, testCategory, "float-function.static.gc", {"10.152\n0\n"});
runner.run_static_test(
env, testCategory, "nested-float-functions.static.gc",
{"i 1.4400 3.4000\nr 10.1523\ni 1.2000 10.1523\nr 17.5432\n17.543 10.152\n0\n"});
}
TEST_F(FloatTests, MinMax) {
runner.run_static_test(env, testCategory, "float-max.static.gc", {"3.70\n0\n"});
runner.run_static_test(env, testCategory, "float-min.static.gc", {"-1.20\n0\n"});
}
-140
View File
@@ -1,140 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct FunctionParam {
// TODO - Not Needed Yet
};
class FunctionTests : public testing::TestWithParam<FunctionParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "functions";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread FunctionTests::runtime_thread;
Compiler FunctionTests::compiler;
GoalTest::CompilerTestRunner FunctionTests::runner;
TEST_F(FunctionTests, Definitions) {
runner.run_static_test(env, testCategory, "defun-return-constant.static.gc", {"12\n"});
runner.run_static_test(env, testCategory, "defun-return-symbol.static.gc", {"42\n"});
}
TEST_F(FunctionTests, ReturnValue) {
runner.run_static_test(env, testCategory, "return.static.gc", {"77\n"});
runner.run_static_test(env, testCategory, "return-arg.static.gc", {"23\n"});
runner.run_static_test(env, testCategory, "return-colors.static.gc", {"77\n"});
}
TEST_F(FunctionTests, Calling) {
runner.run_static_test(env, testCategory, "nested-call.static.gc", {"2\n"});
runner.run_static_test(env, testCategory, "inline-call.static.gc", {"44\n"});
runner.run_static_test(env, testCategory, "simple-call.static.gc", {"30\n"});
}
TEST_F(FunctionTests, Anonymous) {
runner.run_static_test(env, testCategory, "declare-inline.static.gc", {"32\n"});
runner.run_static_test(env, testCategory, "lambda-1.static.gc", {"2\n"});
}
TEST_F(FunctionTests, InlineIsInline) {
auto code = compiler.get_goos().reader.read_from_file(
{"test/goalc/source_templates/functions/declare-inline.static.gc"});
auto compiled = compiler.compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
bool got_mult = false;
for (auto& x : ir) {
EXPECT_EQ(dynamic_cast<IR_FunctionCall*>(x.get()), nullptr);
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im) {
EXPECT_EQ(as_im->get_kind(), IntegerMathKind::IMUL_32);
got_mult = true;
}
}
EXPECT_TRUE(got_mult);
}
TEST_F(FunctionTests, AllowInline) {
auto code = compiler.get_goos().reader.read_from_file(
{"test/goalc/source_templates/functions/inline-call.static.gc"});
auto compiled = compiler.compile_object_file("test-code", code, true);
EXPECT_EQ(compiled->functions().size(), 2);
auto& ir = compiled->top_level_function().code();
int got_mult = 0;
int got_call = 0;
for (auto& x : ir) {
if (dynamic_cast<IR_FunctionCall*>(x.get())) {
got_call++;
}
auto as_im = dynamic_cast<IR_IntegerMath*>(x.get());
if (as_im && as_im->get_kind() == IntegerMathKind::IMUL_32) {
got_mult++;
}
}
EXPECT_EQ(got_mult, 1);
EXPECT_EQ(got_call, 1);
}
TEST_F(FunctionTests, ReturnNone) {
runner.run_static_test(env, testCategory, "function-returning-none.static.gc", {"1\n"});
}
TEST_F(FunctionTests, InlineBlock1) {
runner.run_static_test(env, testCategory, "inline-with-block-1.static.gc", {"1\n"});
}
TEST_F(FunctionTests, InlineBlock2) {
runner.run_static_test(env, testCategory, "inline-with-block-2.static.gc", {"3\n"});
}
TEST_F(FunctionTests, InlineBlock3) {
runner.run_static_test(env, testCategory, "inline-with-block-3.static.gc", {"4\n"});
}
TEST_F(FunctionTests, InlineBlock4) {
runner.run_static_test(env, testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"});
}
TEST_F(FunctionTests, ReturnFromTrick) {
runner.run_static_test(env, testCategory, "return-from-trick.static.gc", {"1\n"});
}
-68
View File
@@ -1,68 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct LibraryParam {
// TODO - Not Needed Yet
};
class LibraryTests : public testing::TestWithParam<LibraryParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "library";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread LibraryTests::runtime_thread;
Compiler LibraryTests::compiler;
GoalTest::CompilerTestRunner LibraryTests::runner;
TEST_F(LibraryTests, Set) {
runner.run_static_test(env, testCategory, "set-symbol.static.gc", {"22\n"});
}
TEST_F(LibraryTests, Protect) {
runner.run_static_test(env, testCategory, "protect.static.gc", {"33\n"});
}
TEST_F(LibraryTests, Align) {
runner.run_static_test(env, testCategory, "align16-1.static.gc", {"80\n"});
runner.run_static_test(env, testCategory, "align16-2.static.gc", {"64\n"});
}
-65
View File
@@ -1,65 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct LogicParam {
// TODO - Not Needed Yet
};
class LogicTests : public testing::TestWithParam<LogicParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "logic";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread LogicTests::runtime_thread;
Compiler LogicTests::compiler;
GoalTest::CompilerTestRunner LogicTests::runner;
TEST_F(LogicTests, LogicalOperators) {
runner.run_static_test(env, testCategory, "logand.static.gc", {"4\n"});
runner.run_static_test(env, testCategory, "logior.static.gc", {"60\n"});
runner.run_static_test(env, testCategory, "logxor.static.gc", {"56\n"});
}
TEST_F(LogicTests, Comparison) {
runner.run_static_test(env, testCategory, "signed-int-compare.static.gc", {"12\n"});
}
-64
View File
@@ -1,64 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct LoopRecurParam {
// TODO - Not Needed Yet
};
class LoopRecurTests : public testing::TestWithParam<LoopRecurParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "loop_recur";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread LoopRecurTests::runtime_thread;
Compiler LoopRecurTests::compiler;
GoalTest::CompilerTestRunner LoopRecurTests::runner;
TEST_F(LoopRecurTests, DoTimes) {
runner.run_static_test(env, testCategory, "dotimes.static.gc", {"4950\n"});
}
TEST_F(LoopRecurTests, Factorial) {
runner.run_static_test(env, testCategory, "factorial-recursive.static.gc", {"3628800\n"});
runner.run_static_test(env, testCategory, "factorial-iterative.static.gc", {"3628800\n"});
}
-63
View File
@@ -1,63 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct MacroParam {
// TODO - Not Needed Yet
};
class MacroTests : public testing::TestWithParam<MacroParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "macros";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread MacroTests::runtime_thread;
Compiler MacroTests::compiler;
GoalTest::CompilerTestRunner MacroTests::runner;
TEST_F(MacroTests, Defsmacro) {
runner.run_static_test(env, testCategory, "defsmacro-defgmacro.static.gc", {"20\n"});
}
TEST_F(MacroTests, Desfun) {
runner.run_static_test(env, testCategory, "desfun.static.gc", {"4\n"});
}
-59
View File
@@ -1,59 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct MethodParam {
// TODO - Not Needed Yet
};
class MethodTests : public testing::TestWithParam<MethodParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "methods";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread MethodTests::runtime_thread;
Compiler MethodTests::compiler;
GoalTest::CompilerTestRunner MethodTests::runner;
TEST_F(MethodTests, DeReference) {
runner.run_static_test(env, testCategory, "methods.static.gc", {"#t#t\n0\n"});
}
-63
View File
@@ -1,63 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct PointerParam {
// TODO - Not Needed Yet
};
class PointerTests : public testing::TestWithParam<PointerParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "pointers";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread PointerTests::runtime_thread;
Compiler PointerTests::compiler;
GoalTest::CompilerTestRunner PointerTests::runner;
TEST_F(PointerTests, DeReference) {
runner.run_static_test(env, testCategory, "deref-simple.static.gc", {"structure\n0\n"});
}
TEST_F(PointerTests, Pointers) {
runner.run_static_test(env, testCategory, "pointers.static.gc", {"13\n"});
}
-88
View File
@@ -1,88 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct StringParam {
// TODO - Not Needed Yet
};
class StringTests : public testing::TestWithParam<StringParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "strings";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread StringTests::runtime_thread;
Compiler StringTests::compiler;
GoalTest::CompilerTestRunner StringTests::runner;
TEST_F(StringTests, Constants) {
// TODO - runner.run_static_test(env, testCategory, "string-constant-1.static.gc");
std::string expected = "\"test string!\"";
runner.run_static_test(env, testCategory, "string-constant-2.static.gc", {expected},
expected.size());
}
TEST_F(StringTests, Symbols) {
runner.run_static_test(env, testCategory, "quote-symbol.static.gc", {"banana\n0\n"});
std::string expected = "test-string";
runner.run_static_test(env, testCategory, "string-symbol.static.gc", {expected}, expected.size());
}
TEST_F(StringTests, Formatting) {
runner.run_static_test(env, testCategory, "format-reg-order.static.gc",
{"test 1 2 3 4 5 6\n0\n"});
}
// expected =
// "test newline\nnewline\ntest tilde ~ \ntest A print boxed-string: \"boxed string!\"\ntest
// A " "print symbol: a-symbol\ntest A make boxed object longer: \"srt\"!\ntest A
// " "non-default pad: zzzzzzpad-me\ntest A shorten(4): a23~\ntest A don'tchange(4):
// a234\ntest A " "shorten with pad(4): sho~\ntest A a few things \"one thing\" a-second
// integer #<compiled " "function @ #x161544>\n";
//
// expected += "test S a string a-symbol another string!\n";
// expected += "test C ) ]\n";
// expected += "test P (no type) #<compiled function @ #x161544>\n";
// expected += "test P (with type) 1447236\n";
//
// // todo, finish format testing.
// runner.run_test_from_file("test-format.gc", {expected}, expected.size());
-62
View File
@@ -1,62 +0,0 @@
#include <thread>
#include <chrono>
#include "gtest/gtest.h"
#include "game/runtime.h"
#include "goalc/listener/Listener.h"
#include "goalc/compiler/Compiler.h"
#include "inja.hpp"
#include "third-party/json.hpp"
#include <test/goalc/framework/test_runner.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#include <iostream>
#include <random>
#include <filesystem>
struct SymbolParam {
// TODO - Not Needed Yet
};
class SymbolTests : public testing::TestWithParam<SymbolParam> {
public:
static void SetUpTestSuite() {
runtime_thread = std::thread((GoalTest::runtime_no_kernel));
runner.c = &compiler;
}
static void TearDownTestSuite() {
compiler.shutdown_target();
runtime_thread.join();
}
void SetUp() {
GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory));
GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory));
}
void TearDown() {}
static std::thread runtime_thread;
static Compiler compiler;
static GoalTest::CompilerTestRunner runner;
std::string testCategory = "symbols";
inja::Environment env{GoalTest::getTemplateDir(testCategory),
GoalTest::getGeneratedDir(testCategory)};
};
std::thread SymbolTests::runtime_thread;
Compiler SymbolTests::compiler;
GoalTest::CompilerTestRunner SymbolTests::runner;
TEST_F(SymbolTests, GetSymbol) {
runner.run_static_test(env, testCategory, "get-symbol-1.static.gc",
{"1342756\n"}); // 0x147d24 in hex
runner.run_static_test(env, testCategory, "get-symbol-2.static.gc",
{"1342764\n"}); // 0x147d2c in hex
}
+49 -1
View File
@@ -93,4 +93,52 @@ TEST_F(VariableTests, StackArrayAlignment) {
TEST_F(VariableTests, StackStructureAlignment) {
runner.run_static_test(env, testCategory, "stack-structure-align.gc", {"1234\n"});
}
}
TEST_F(VariableTests, GetSymbol) {
runner.run_static_test(env, testCategory, "get-symbol-1.static.gc",
{"1342756\n"}); // 0x147d24 in hex
runner.run_static_test(env, testCategory, "get-symbol-2.static.gc",
{"1342764\n"}); // 0x147d2c in hex
}
TEST_F(VariableTests, Constants) {
// TODO - runner.run_static_test(env, testCategory, "string-constant-1.static.gc");
std::string expected = "\"test string!\"";
runner.run_static_test(env, testCategory, "string-constant-2.static.gc", {expected},
expected.size());
}
TEST_F(VariableTests, Symbols) {
runner.run_static_test(env, testCategory, "quote-symbol.static.gc", {"banana\n0\n"});
std::string expected = "test-string";
runner.run_static_test(env, testCategory, "string-symbol.static.gc", {expected}, expected.size());
}
TEST_F(VariableTests, Formatting) {
runner.run_static_test(env, testCategory, "format-reg-order.static.gc",
{"test 1 2 3 4 5 6\n0\n"});
}
TEST_F(VariableTests, DeReference) {
runner.run_static_test(env, testCategory, "deref-simple.static.gc", {"structure\n0\n"});
}
TEST_F(VariableTests, Pointers) {
runner.run_static_test(env, testCategory, "pointers.static.gc", {"13\n"});
}
// expected =
// "test newline\nnewline\ntest tilde ~ \ntest A print boxed-string: \"boxed string!\"\ntest
// A " "print symbol: a-symbol\ntest A make boxed object longer: \"srt\"!\ntest A
// " "non-default pad: zzzzzzpad-me\ntest A shorten(4): a23~\ntest A don'tchange(4):
// a234\ntest A " "shorten with pad(4): sho~\ntest A a few things \"one thing\" a-second
// integer #<compiled " "function @ #x161544>\n";
//
// expected += "test S a string a-symbol another string!\n";
// expected += "test C ) ]\n";
// expected += "test P (no type) #<compiled function @ #x161544>\n";
// expected += "test P (with type) 1447236\n";
//
// // todo, finish format testing.
// runner.run_test_from_file("test-format.gc", {expected}, expected.size());
+1 -1
View File
@@ -58,7 +58,7 @@ TEST(Listener, CheckConnectionStaysAlive) {
}
EXPECT_TRUE(s.check_for_listener());
std::this_thread::sleep_for(std::chrono::seconds(2)); // sorry for making tests slow.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_TRUE(s.check_for_listener());
EXPECT_TRUE(l.is_connected());
}