#include "DataFormatters/FormatterBytecode.h" #include "lldb/Utility/StreamString.h" #include "gtest/gtest.h" using namespace lldb_private; using namespace lldb; using namespace FormatterBytecode; using llvm::StringRef; namespace { class FormatterBytecodeTest : public ::testing::Test {}; bool Interpret(std::vector code, DataStack &data) { auto buf = StringRef(reinterpret_cast(code.data()), code.size()); std::vector control({buf}); if (auto error = Interpret(control, data, sel_summary)) { #ifndef NDEBUG llvm::errs() << llvm::toString(std::move(error)) << '\n'; #else llvm::consumeError(std::move(error)); #endif return false; } return true; } } // namespace TEST_F(FormatterBytecodeTest, StackOps) { { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 23, op_dup, op_plus}, data)); ASSERT_EQ(data.Pop(), 46u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_drop}, data)); ASSERT_EQ(data.size(), 0u); } { for (unsigned char i = 0; i < 3; ++i) { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_lit_uint, 2, op_lit_uint, i, op_pick}, data)); ASSERT_EQ(data.Pop(), i); } } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_over}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_swap}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_EQ(data.Pop(), 1u); } { DataStack data; ASSERT_TRUE(Interpret( {op_lit_uint, 0, op_lit_uint, 1, op_lit_uint, 2, op_rot}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_EQ(data.Pop(), 0u); ASSERT_EQ(data.Pop(), 2u); } } TEST_F(FormatterBytecodeTest, ControlOps) { { DataStack data; ASSERT_TRUE( Interpret({op_lit_uint, 0, op_begin, 2, op_lit_uint, 42, op_if}, data)); ASSERT_EQ(data.size(), 0u); } { DataStack data; ASSERT_TRUE( Interpret({op_lit_uint, 1, op_begin, 2, op_lit_uint, 42, op_if}, data)); ASSERT_EQ(data.Pop(), 42u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_begin, 2, op_lit_uint, 42, op_begin, 2, op_lit_uint, 23, op_ifelse}, data)); ASSERT_EQ(data.Pop(), 23u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_begin, 2, op_lit_uint, 42, op_begin, 2, op_lit_uint, 23, op_ifelse}, data)); ASSERT_EQ(data.Pop(), 42u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_begin, 3, op_lit_uint, 42, op_return, op_if, op_lit_uint, 23}, data)); ASSERT_EQ(data.Pop(), 42u); } } TEST_F(FormatterBytecodeTest, ConversionOps) { { DataStack data(lldb::ValueObjectSP{}); ASSERT_TRUE(Interpret({op_is_null}, data)); ASSERT_EQ(data.Pop(), 1u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1u, op_as_int}, data)); ASSERT_EQ(data.Pop(), 1); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_int, 126, op_as_uint}, data)); ASSERT_EQ(data.Pop(), ~1ULL); } } TEST_F(FormatterBytecodeTest, ArithOps) { { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 2, op_lit_uint, 3, op_plus}, data)); ASSERT_EQ(data.Pop(), 5u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 3, op_lit_uint, 2, op_minus}, data)); ASSERT_EQ(data.Pop(), 1u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 3, op_lit_uint, 2, op_mul}, data)); ASSERT_EQ(data.Pop(), 6u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 6, op_lit_uint, 2, op_div}, data)); ASSERT_EQ(data.Pop(), 3u); } { DataStack data; ASSERT_FALSE(Interpret({op_lit_uint, 23, op_lit_uint, 0, op_div}, data)); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 2, op_shl}, data)); ASSERT_EQ(data.Pop(), 4u); } { DataStack data; unsigned char minus_one = 127; ASSERT_FALSE( Interpret({op_lit_int, minus_one, op_lit_uint, 2, op_shl}, data)); unsigned char minus_two = 126; ASSERT_TRUE( Interpret({op_lit_int, minus_two, op_lit_uint, 1, op_shr}, data)); ASSERT_EQ(data.Pop(), -1); } { DataStack data; ASSERT_FALSE(Interpret({op_lit_uint, 1, op_lit_uint, 65, op_shl}, data)); ASSERT_FALSE(Interpret({op_lit_uint, 1, op_lit_uint, 65, op_shr}, data)); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_and}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_and}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_or}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_or}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_or}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_xor}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_xor}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_xor}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_not}, data)); ASSERT_EQ(data.Pop(), 0xffffffffffffffff); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_eq}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_eq}, data)); ASSERT_EQ(data.Pop(), 1u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_neq}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_neq}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_lt}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_lt}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_lt}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_gt}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_gt}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_gt}, data)); ASSERT_EQ(data.Pop(), 0u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_le}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_le}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_le}, data)); ASSERT_EQ(data.Pop(), 1u); } { DataStack data; ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_ge}, data)); ASSERT_EQ(data.Pop(), 0u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_ge}, data)); ASSERT_EQ(data.Pop(), 1u); ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_ge}, data)); ASSERT_EQ(data.Pop(), 1u); } } TEST_F(FormatterBytecodeTest, CallOps) { { DataStack data; data.Push(std::string{"hello"}); ASSERT_TRUE(Interpret({op_lit_selector, sel_strlen, op_call}, data)); ASSERT_EQ(data.Pop(), 5u); } { DataStack data; data.Push(std::string{"A"}); data.Push(std::string{"B"}); data.Push(std::string{"{1}{0}"}); ASSERT_TRUE(Interpret({op_lit_selector, sel_fmt, op_call}, data)); ASSERT_EQ(data.Pop(), "BA"); } { DataStack data; data.Push(std::string{"{0}"}); ASSERT_FALSE(Interpret({op_lit_selector, sel_fmt, op_call}, data)); } }