#include "gtest/gtest.h" #include "gmock/gmock.h" #include #include #include "bytearray.hh" #include "bytecodeprototype.hh" #include "bytecode.hh" using namespace tyche; static void print(std::vector const& data) { for (size_t i = 0; i < data.size(); ++i) { if (i % 16 == 0) printf("%04X : ", i); printf("%02X ", data.at(i)); if (i % 16 == 15) printf("\n"); } printf("\n"); } TEST(ByteArray, ByteArray) { auto test = [](std::function const& f, std::vector const& expected) { ByteArray ba; f(ba); ASSERT_EQ(ba.data().size(), expected.size()); ASSERT_EQ(std::memcmp(ba.data().data(), expected.data(), ba.data().size()), 0); }; #define TESTX(a, ...) test([](ByteArray& ba) { a; }, std::vector({ __VA_ARGS__ })); TESTX(ba.set_byte(1, 0xab), 0x00, 0xab) ByteArray ba; ba.set_byte(1, 0xab); ASSERT_EQ(ba.get_byte(1), 0xab); ba.set_int(1, 12); ASSERT_EQ(ba.get_int(1), std::make_pair(12, 1)); ba.set_int(1, -12); ASSERT_EQ(ba.get_int(1), std::make_pair(-12, 1)); ba.set_int(1, 5000); ASSERT_EQ(ba.get_int(1), std::make_pair(5000, 2)); ba.set_int(1, 5000300); ASSERT_EQ(ba.get_int(1), std::make_pair(5000300, 4)); ba.set_int(1, -5000300); ASSERT_EQ(ba.get_int(1), std::make_pair(-5000300, 4)); ba.set_float(1, 3.14); ASSERT_FLOAT_EQ(ba.get_float(1).first, 3.14); ba.set_float(1, -3.14); ASSERT_FLOAT_EQ(ba.get_float(1).first, -3.14); ba.set_float(1, -5000300.1324); ASSERT_FLOAT_EQ(ba.get_float(1).first, -5000300.1324); ba.set_string(1, "Hello world!"); ASSERT_EQ(ba.get_string(1), std::make_pair("Hello world!", 13)); #undef TESTX } TEST(Bytecode, Constants) { BytecodePrototype bp; bp.constants.emplace_back(42); bp.constants.emplace_back("HELLO"); std::vector expected = { // header 0x38, 0xc1, 0xb3, 0x74, // magic 0x01, 0x00, 0x00, 0x00, // version 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // index 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, // constants 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // functions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // constant indexes 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // constant values 0x54, 'H', 'E', 'L', 'L', 'O', 0x00 }; ByteArray ba = Bytecode::generate(bp); ASSERT_EQ(ba.data(), expected); } TEST(Bytecode, Code) { BytecodePrototype bp; auto& f = bp.functions.emplace_back(0, 0); f.code.append_byte(0x68); f.code.append_int(42); auto& f2 = bp.functions.emplace_back(2, 1); f2.code.append_byte(0x42); std::vector expected = { // header 0x38, 0xc1, 0xb3, 0x74, // magic 0x01, 0x00, 0x00, 0x00, // version 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // index 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // constants 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, // variables 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // function definitions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, // code 0x68, 0x54, 0x42, }; ByteArray ba = Bytecode::generate(bp); ASSERT_EQ(ba.data(), expected); } TEST(Bytecode, Parsing) { // write bytecode BytecodePrototype bp; bp.constants.emplace_back(42); bp.constants.emplace_back(3.14f); bp.constants.emplace_back("HELLO"); auto& f = bp.functions.emplace_back(0, 0); f.code.append_byte(0x68); f.code.append_int(42); auto& f2 = bp.functions.emplace_back(2, 1); f2.code.append_byte(0x42); ByteArray ba = Bytecode::generate(bp); // read bytecode Bytecode bc2(std::move(ba)); ASSERT_EQ(bc2.n_constants(), 3); ASSERT_EQ(bc2.n_functions(), 2); } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }