diff --git a/include/scratchcpp/value.h b/include/scratchcpp/value.h index 7f872213..ee9aab9c 100644 --- a/include/scratchcpp/value.h +++ b/include/scratchcpp/value.h @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include "global.h" @@ -40,14 +42,28 @@ class LIBSCRATCHCPP_EXPORT Value Value(float numberValue) : m_type(Type::Double) { - m_doubleValue = numberValue; + if (isInf(numberValue)) + m_type = Type::Infinity; + else if (isNegativeInf(numberValue)) + m_type = Type::NegativeInfinity; + else if (std::isnan(numberValue)) + m_type = Type::NaN; + else + m_doubleValue = floatToDouble(numberValue); } /*! Constructs a number Value. */ Value(double numberValue) : m_type(Type::Double) { - m_doubleValue = numberValue; + if (isInf(numberValue)) + m_type = Type::Infinity; + else if (isNegativeInf(numberValue)) + m_type = Type::NegativeInfinity; + else if (std::isnan(numberValue)) + m_type = Type::NaN; + else + m_doubleValue = numberValue; } /*! Constructs a number Value. */ @@ -82,8 +98,14 @@ class LIBSCRATCHCPP_EXPORT Value Value(const std::string &stringValue) : m_type(Type::String) { - new (&m_stringValue) std::string(stringValue); - initString(stringValue); + if (stringValue == "Infinity") + m_type = Type::Infinity; + else if (stringValue == "-Infinity") + m_type = Type::NegativeInfinity; + else if (stringValue == "NaN") + m_type = Type::NaN; + else + new (&m_stringValue) std::string(stringValue); } /*! Constructs a string Value. */ @@ -139,17 +161,104 @@ class LIBSCRATCHCPP_EXPORT Value Type type() const { return m_type; } /*! Returns true if the value is infinity. */ - bool isInfinity() const { return m_type == Type::Infinity; } + bool isInfinity() const + { + switch (m_type) { + case Type::Infinity: + return true; + case Type::Integer: + return isInf(m_intValue); + case Type::Double: + return isInf(m_doubleValue); + case Type::String: + return m_stringValue == "Infinity"; + default: + return false; + } + } /*! Returns true if the value is negative infinity. */ - bool isNegativeInfinity() const { return m_type == Type::NegativeInfinity; } + bool isNegativeInfinity() const + { + switch (m_type) { + case Type::NegativeInfinity: + return true; + case Type::Integer: + return isNegativeInf(-m_intValue); + case Type::Double: + return isNegativeInf(-m_doubleValue); + case Type::String: + return m_stringValue == "-Infinity"; + default: + return false; + } + } /*! Returns true if the value is NaN (Not a Number). */ - bool isNaN() const { return m_type == Type::NaN; } + bool isNaN() const + { + switch (m_type) { + case Type::NaN: + return true; + case Type::Double: + assert(!std::isnan(m_doubleValue)); + return std::isnan(m_doubleValue); + case Type::String: + return m_stringValue == "NaN"; + default: + return false; + } + } /*! Returns true if the value is a number. */ bool isNumber() const { return m_type == Type::Integer || m_type == Type::Double; } + /*! Returns true if the value is a number or can be converted to a number. */ + bool isValidNumber() const + { + if (isNaN()) + return false; + + if (isInfinity() || isNegativeInfinity()) + return true; + + assert(m_type != Type::Infinity && m_type != Type::NegativeInfinity); + + switch (m_type) { + case Type::Integer: + case Type::Double: + case Type::Bool: + return true; + case Type::String: + return m_stringValue.empty() || checkString(m_stringValue) > 0; + default: + return false; + } + } + + /*! Returns true if this value represents a round integer. */ + bool isInt() const + { + // https://github.com/scratchfoundation/scratch-vm/blob/112989da0e7306eeb405a5c52616e41c2164af24/src/util/cast.js#L157-L181 + switch (m_type) { + case Type::Integer: + case Type::Bool: + case Type::Infinity: + case Type::NegativeInfinity: + case Type::NaN: + return true; + case Type::Double: { + double intpart; + std::modf(m_doubleValue, &intpart); + return m_doubleValue == intpart; + } + case Type::String: + return m_stringValue.find('.') == std::string::npos; + } + + return false; + } + /*! Returns true if the value is a boolean. */ bool isBool() const { return m_type == Type::Bool; } @@ -162,16 +271,9 @@ class LIBSCRATCHCPP_EXPORT Value /*! Returns the long representation of the value. */ long toLong() const { - if (static_cast(m_type) < 0) { - switch (m_type) { - case Type::Infinity: - return std::numeric_limits::infinity(); - case Type::NegativeInfinity: - return -std::numeric_limits::infinity(); - default: - return 0; - } - } else { + if (static_cast(m_type) < 0) + return 0; + else { switch (m_type) { case Type::Integer: return m_intValue; @@ -375,8 +477,17 @@ class LIBSCRATCHCPP_EXPORT Value if (m_type == Type::String) m_stringValue.~basic_string(); - m_type = Type::Double; - m_doubleValue = v; + if (isInf(v)) + m_type = Type::Infinity; + else if (isNegativeInf(v)) + m_type = Type::NegativeInfinity; + else if (std::isnan(v)) + m_type = Type::NaN; + else { + m_type = Type::Double; + m_doubleValue = floatToDouble(v); + } + return *this; } @@ -385,8 +496,16 @@ class LIBSCRATCHCPP_EXPORT Value if (m_type == Type::String) m_stringValue.~basic_string(); - m_type = Type::Double; - m_doubleValue = v; + if (isInf(v)) + m_type = Type::Infinity; + else if (isNegativeInf(v)) + m_type = Type::NegativeInfinity; + else if (std::isnan(v)) + m_type = Type::NaN; + else { + m_type = Type::Double; + m_doubleValue = v; + } return *this; } @@ -422,30 +541,33 @@ class LIBSCRATCHCPP_EXPORT Value const Value &operator=(const std::string &v) { - if (m_type == Type::String) - m_stringValue = v; - else { - new (&m_stringValue) std::string(v); - m_type = Type::String; - } + if (v == "Infinity") { + if (m_type == Type::String) + m_stringValue.~basic_string(); - initString(v); - return *this; - } + m_type = Type::Infinity; + } else if (v == "-Infinity") { + if (m_type == Type::String) + m_stringValue.~basic_string(); - const Value &operator=(const char *v) - { - if (m_type == Type::String) + m_type = Type::NegativeInfinity; + } else if (v == "NaN") { + if (m_type == Type::String) + m_stringValue.~basic_string(); + + m_type = Type::NaN; + } else if (m_type == Type::String) m_stringValue = v; else { new (&m_stringValue) std::string(v); m_type = Type::String; } - initString(v); return *this; } + const Value &operator=(const char *v) { return (*this = std::string(v)); } + const Value &operator=(const Value &v) { switch (v.m_type) { @@ -495,59 +617,22 @@ class LIBSCRATCHCPP_EXPORT Value std::string m_stringValue; }; - // -1 - error // 0 - is string // 1 - is long // 2 - is double - static int checkString(const std::string &str, long *longValue, double *doubleValue) + static int checkString(const std::string &str) { - if (!longValue || !doubleValue) - return -1; - bool ok; if ((str.find_first_of('.') == std::string::npos) && (str.find_first_of('e') == std::string::npos) && (str.find_first_of('E') == std::string::npos)) { - *longValue = stringToLong(str, &ok); + stringToLong(str, &ok); return ok ? 1 : 0; } else { - *doubleValue = stringToDouble(str, &ok); + stringToDouble(str, &ok); return ok ? 2 : 0; } } - void initString(const std::string &str) - { - if (str.empty()) - return; - else if (str == "Infinity") { - m_type = Type::Infinity; - return; - } else if (str == "-Infinity") { - m_type = Type::NegativeInfinity; - return; - } else if (str == "NaN") { - m_type = Type::NaN; - return; - } - - long l; - double d; - int type = checkString(str, &l, &d); - - switch (type) { - case 1: - *this = l; - m_type = Type::Integer; - break; - case 2: - *this = d; - m_type = Type::Double; - break; - default: - break; - } - } - double getNumber(bool *ok = nullptr) const { // Equivalent to JavaScript Number(), *ok == false means NaN @@ -588,8 +673,6 @@ class LIBSCRATCHCPP_EXPORT Value } } - void initString(const char *str) { initString(std::string(str)); } - Type m_type; friend bool operator==(const Value &v1, const Value &v2) @@ -921,7 +1004,7 @@ class LIBSCRATCHCPP_EXPORT Value } } - static const std::string digits = "0123456789+-"; + static const std::string digits = "0123456789.eE+-"; for (char c : s) { if (digits.find(c) == std::string::npos) { @@ -943,7 +1026,17 @@ class LIBSCRATCHCPP_EXPORT Value static std::string doubleToString(double v) { std::stringstream stream; - stream << v; + + if (v != 0) { + const int exponent = std::log10(std::abs(v)); + + if (exponent > 20) + stream << std::scientific << std::setprecision(digitCount(v / std::pow(10, exponent + 1)) - 1) << v; + else + stream << std::setprecision(std::max(16u, digitCount(v))) << v; + } else + stream << std::setprecision(std::max(16u, digitCount(v))) << v; + std::string s = stream.str(); std::size_t index; @@ -961,6 +1054,45 @@ class LIBSCRATCHCPP_EXPORT Value return s; } + + static double floatToDouble(float v) + { + unsigned int digits = digitCount(v); + double f = std::pow(10, digits); + return std::round(v * f) / f; + } + + template + static unsigned int digitCount(T v) + { + const T epsilon = 0.0000001; + T intpart; + unsigned int i = 1, j = 0; + + if (std::abs(std::modf(v, &intpart)) >= epsilon) { + T tmp_intpart; + + while (std::abs(std::modf(v * std::pow(10, i), &tmp_intpart)) >= epsilon) + i++; + } + + while (std::abs(intpart / pow(10, j)) >= 1.0) + j++; + + return i + j; + } + + template + static bool isInf(T v) + { + return v > 0 && std::isinf(v); + } + + template + static bool isNegativeInf(T v) + { + return v < 0 && std::isinf(v); + } }; } // namespace libscratchcpp diff --git a/src/blocks/looksblocks.cpp b/src/blocks/looksblocks.cpp index cc1eb369..4c98e26b 100644 --- a/src/blocks/looksblocks.cpp +++ b/src/blocks/looksblocks.cpp @@ -350,6 +350,9 @@ void LooksBlocks::compileSwitchCostumeTo(Compiler *compiler) if (v.type() == Value::Type::Integer) { compiler->addConstValue(v.toLong() - 1); compiler->addFunctionCall(&switchCostumeToByIndex); + } else { + compiler->addInput(input); + compiler->addFunctionCall(&switchCostumeTo); } } } else { @@ -394,6 +397,9 @@ void LooksBlocks::compileSwitchBackdropTo(Compiler *compiler) if (v.type() == Value::Type::Integer) { compiler->addConstValue(v.toLong() - 1); compiler->addFunctionCall(&switchBackdropToByIndex); + } else { + compiler->addInput(input); + compiler->addFunctionCall(&switchBackdropTo); } } } else { @@ -433,6 +439,9 @@ void LooksBlocks::compileSwitchBackdropToAndWait(Compiler *compiler) if (v.type() == Value::Type::Integer) { compiler->addConstValue(v.toLong() - 1); compiler->addFunctionCall(&switchBackdropToByIndexAndWait); + } else { + compiler->addInput(input); + compiler->addFunctionCall(&switchBackdropToAndWait); } } } else { @@ -936,7 +945,7 @@ unsigned int LooksBlocks::switchCostumeTo(VirtualMachine *vm) else if (nameStr == "previous costume") previousCostume(vm); else { - if (name->type() == Value::Type::Integer) + if (name->isValidNumber()) setCostumeByIndex(target, name->toLong() - 1); } } else @@ -994,7 +1003,7 @@ void LooksBlocks::switchBackdropToImpl(VirtualMachine *vm) else if (nameStr == "random backdrop") { randomBackdropImpl(vm); } else { - if (name->type() == Value::Type::Integer) + if (name->isValidNumber()) setCostumeByIndex(stage, name->toLong() - 1); } } else diff --git a/src/blocks/soundblocks.cpp b/src/blocks/soundblocks.cpp index fab7302e..7106b6ca 100644 --- a/src/blocks/soundblocks.cpp +++ b/src/blocks/soundblocks.cpp @@ -66,7 +66,7 @@ bool SoundBlocks::compilePlayCommon(Compiler *compiler, bool untilDone, bool *by if (index == -1) { Value v(value); - if (v.type() == Value::Type::Integer) { + if (v.isValidNumber() && !v.isInfinity() && !v.isNegativeInfinity() && !(v.isString() && v.toString().empty())) { compiler->addConstValue(v.toLong() - 1); compiler->addFunctionCall(untilDone ? &playByIndexUntilDone : &playByIndex); @@ -166,7 +166,7 @@ Sound *SoundBlocks::playCommon(VirtualMachine *vm) return sound; } - else if (name->type() == Value::Type::Integer) { + if (name->isValidNumber() && !name->isInfinity() && !name->isNegativeInfinity() && !(name->isString() && name->toString().empty())) { sound = getSoundByIndex(target, name->toLong() - 1); if (sound) { @@ -245,7 +245,7 @@ unsigned int SoundBlocks::checkSound(VirtualMachine *vm) if (target) { Sound *sound = target->soundAt(target->findSound(name->toString())).get(); - if (!sound && name->type() == Value::Type::Integer) + if (!sound && name->isValidNumber() && !name->isInfinity() && !name->isNegativeInfinity() && !(name->isString() && name->toString().empty())) sound = getSoundByIndex(target, name->toLong() - 1); if (sound) { diff --git a/src/engine/virtualmachine_p.cpp b/src/engine/virtualmachine_p.cpp index cdbc5c9a..b9a99521 100644 --- a/src/engine/virtualmachine_p.cpp +++ b/src/engine/virtualmachine_p.cpp @@ -438,7 +438,7 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) DISPATCH(); OP(RANDOM) : - if ((READ_REG(0, 2)->type() == Value::Type::Integer) && (READ_REG(1, 2)->type() == Value::Type::Integer)) REPLACE_RET_VALUE(rng->randint(READ_REG(0, 2)->toInt(), READ_REG(1, 2)->toInt()), 2); + if (READ_REG(0, 2)->isInt() && READ_REG(1, 2)->isInt()) REPLACE_RET_VALUE(rng->randint(READ_REG(0, 2)->toInt(), READ_REG(1, 2)->toInt()), 2); else REPLACE_RET_VALUE(rng->randintDouble(READ_REG(0, 2)->toDouble(), READ_REG(1, 2)->toDouble()), 2); FREE_REGS(1); DISPATCH(); @@ -621,7 +621,10 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) const Value *indexValue = READ_LAST_REG(); size_t index; List *list = lists[*++pos]; - if (indexValue->isString()) { + if (indexValue->isValidNumber()) { + index = indexValue->toLong(); + FIX_LIST_INDEX(index, list->size()); + } else { const std::string &str = indexValue->toString(); if (str == "last") { index = list->size(); @@ -633,9 +636,6 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) index = size == 0 ? 0 : rng->randint(1, size); } else index = 0; - } else { - index = indexValue->toLong(); - FIX_LIST_INDEX(index, list->size()); } if (index != 0) list->removeAt(index - 1); @@ -652,7 +652,10 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) const Value *indexValue = READ_REG(1, 2); size_t index; List *list = lists[*++pos]; - if (indexValue->isString()) { + if (indexValue->isValidNumber()) { + index = indexValue->toLong(); + FIX_LIST_INDEX(index, list->size()); + } else { const std::string &str = indexValue->toString(); if (str == "last") { list->push_back(*READ_REG(0, 2)); @@ -662,9 +665,6 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) index = size == 0 ? 1 : rng->randint(1, size); } else index = 0; - } else { - index = indexValue->toLong(); - FIX_LIST_INDEX(index, list->size()); } if ((index != 0) || list->empty()) { if (list->empty()) @@ -681,7 +681,10 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) const Value *indexValue = READ_REG(0, 2); size_t index; List *list = lists[*++pos]; - if (indexValue->isString()) { + if (indexValue->isValidNumber()) { + index = indexValue->toLong(); + FIX_LIST_INDEX(index, list->size()); + } else { std::string str = indexValue->toString(); if (str == "last") index = list->size(); @@ -690,9 +693,6 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) index = size == 0 ? 0 : rng->randint(1, size); } else index = 0; - } else { - index = indexValue->toLong(); - FIX_LIST_INDEX(index, list->size()); } if (index != 0) list->operator[](index - 1) = *READ_REG(1, 2); @@ -705,7 +705,10 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) const Value *indexValue = READ_LAST_REG(); size_t index; List *list = lists[*++pos]; - if (indexValue->isString()) { + if (indexValue->isValidNumber()) { + index = indexValue->toLong(); + FIX_LIST_INDEX(index, list->size()); + } else { std::string str = indexValue->toString(); if (str == "last") index = list->size(); @@ -714,9 +717,6 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset) index = size == 0 ? 0 : rng->randint(1, size); } else index = 0; - } else { - index = indexValue->toLong(); - FIX_LIST_INDEX(index, list->size()); } if (index == 0) { REPLACE_RET_VALUE("", 1); diff --git a/src/internal/reader_common.h b/src/internal/reader_common.h index 840a1aa3..ac8bde38 100644 --- a/src/internal/reader_common.h +++ b/src/internal/reader_common.h @@ -15,8 +15,14 @@ Value jsonToValue(nlohmann::json value) return value.get(); else if (value.is_boolean()) return value.get(); - else + else if (value.is_number_integer() || value.is_number_unsigned()) + return value.get(); + else if (value.is_number_float()) + return value.get(); + else { + assert(!value.is_number()); return value.dump(); + } } } // namespace libscratchcpp diff --git a/src/scratch/list.cpp b/src/scratch/list.cpp index f2e2c16b..043077ba 100644 --- a/src/scratch/list.cpp +++ b/src/scratch/list.cpp @@ -74,9 +74,15 @@ std::string List::toString() const bool digits = true; for (const auto &item : *this) { - if (item.type() == Value::Type::Integer) { + if (item.isValidNumber() && !item.toString().empty()) { + double doubleNum = item.toDouble(); long num = item.toLong(); + if (doubleNum != num) { + digits = false; + break; + } + if (num < 0 || num >= 10) { digits = false; break; diff --git a/test/blocks/looks_blocks_test.cpp b/test/blocks/looks_blocks_test.cpp index 288c4781..2bf1e44a 100644 --- a/test/blocks/looks_blocks_test.cpp +++ b/test/blocks/looks_blocks_test.cpp @@ -1469,6 +1469,7 @@ TEST_F(LooksBlocksTest, SwitchCostumeTo) // Test without any costumes first compiler.setBlock(block1); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeTo)).WillOnce(Return(3)); LooksBlocks::compileSwitchCostumeTo(&compiler); target.addCostume(std::make_shared("costume1", "c1", "svg")); @@ -1480,19 +1481,19 @@ TEST_F(LooksBlocksTest, SwitchCostumeTo) target.addCostume(std::make_shared("costume3", "c3", "svg")); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeTo)).WillOnce(Return(3)); compiler.setBlock(block2); LooksBlocks::compileSwitchCostumeTo(&compiler); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeTo)).WillOnce(Return(3)); compiler.setBlock(block3); LooksBlocks::compileSwitchCostumeTo(&compiler); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeTo)).WillOnce(Return(3)); compiler.setBlock(block4); LooksBlocks::compileSwitchCostumeTo(&compiler); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchCostumeTo)).WillOnce(Return(3)); compiler.setBlock(block5); LooksBlocks::compileSwitchCostumeTo(&compiler); @@ -1535,7 +1536,7 @@ TEST_F(LooksBlocksTest, SwitchCostumeTo) vm::OP_CONST, 0, vm::OP_EXEC, - 0, + 3, vm::OP_CONST, 1, vm::OP_EXEC, @@ -1543,36 +1544,40 @@ TEST_F(LooksBlocksTest, SwitchCostumeTo) vm::OP_CONST, 2, vm::OP_EXEC, - 0, + 3, vm::OP_CONST, 3, vm::OP_EXEC, - 0, + 3, vm::OP_CONST, 4, vm::OP_EXEC, - 0, + 3, vm::OP_CONST, 5, vm::OP_EXEC, + 3, + vm::OP_CONST, + 6, + vm::OP_EXEC, 0, vm::OP_EXEC, 1, vm::OP_CONST, - 6, + 7, vm::OP_EXEC, 0, vm::OP_EXEC, 2, vm::OP_CONST, - 7, + 8, vm::OP_EXEC, 0, vm::OP_NULL, vm::OP_EXEC, 3, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues(), std::vector({ 1, -1, 0, 1, 3, 3, 4, 5 })); + ASSERT_EQ(compiler.constValues(), std::vector({ "costume2", 1, "0", "1", "2", "4", 3, 4, 5 })); } TEST_F(LooksBlocksTest, SwitchCostumeToImpl) @@ -1887,6 +1892,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropTo) // Test without any backdrops first EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropTo)).WillOnce(Return(4)); compiler.setBlock(block1); LooksBlocks::compileSwitchBackdropTo(&compiler); @@ -1901,22 +1907,22 @@ TEST_F(LooksBlocksTest, SwitchBackdropTo) stage.addCostume(std::make_shared("backdrop3", "b3", "svg")); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropTo)).WillOnce(Return(4)); compiler.setBlock(block2); LooksBlocks::compileSwitchBackdropTo(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropTo)).WillOnce(Return(4)); compiler.setBlock(block3); LooksBlocks::compileSwitchBackdropTo(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropTo)).WillOnce(Return(4)); compiler.setBlock(block4); LooksBlocks::compileSwitchBackdropTo(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndex)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropTo)).WillOnce(Return(4)); compiler.setBlock(block5); LooksBlocks::compileSwitchBackdropTo(&compiler); @@ -1977,7 +1983,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropTo) vm::OP_CONST, 0, vm::OP_EXEC, - 0, + 4, vm::OP_CONST, 1, vm::OP_EXEC, @@ -1985,42 +1991,46 @@ TEST_F(LooksBlocksTest, SwitchBackdropTo) vm::OP_CONST, 2, vm::OP_EXEC, - 0, + 4, vm::OP_CONST, 3, vm::OP_EXEC, - 0, + 4, vm::OP_CONST, 4, vm::OP_EXEC, - 0, + 4, vm::OP_CONST, 5, vm::OP_EXEC, + 4, + vm::OP_CONST, + 6, + vm::OP_EXEC, 0, vm::OP_EXEC, 1, vm::OP_CONST, - 6, + 7, vm::OP_EXEC, 0, vm::OP_EXEC, 2, vm::OP_CONST, - 7, + 8, vm::OP_EXEC, 0, vm::OP_EXEC, 3, vm::OP_CONST, - 8, + 9, vm::OP_EXEC, 0, vm::OP_NULL, vm::OP_EXEC, 4, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues(), std::vector({ 1, -1, 0, 1, 3, 3, 4, 5, 6 })); + ASSERT_EQ(compiler.constValues(), std::vector({ "backdrop2", 1, "0", "1", "2", "4", 3, 4, 5, 6 })); } TEST_F(LooksBlocksTest, SwitchBackdropToImpl) @@ -2294,6 +2304,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) // Test without any backdrops first EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToAndWait)).WillOnce(Return(4)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::backdropNumber)).WillOnce(Return(6)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::checkBackdropScripts)).WillOnce(Return(5)); compiler.setBlock(block1); @@ -2312,28 +2323,28 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) stage.addCostume(std::make_shared("backdrop3", "b3", "svg")); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndexAndWait)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToAndWait)).WillOnce(Return(4)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::backdropNumber)).WillOnce(Return(6)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::checkBackdropScripts)).WillOnce(Return(5)); compiler.setBlock(block2); LooksBlocks::compileSwitchBackdropToAndWait(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndexAndWait)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToAndWait)).WillOnce(Return(4)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::backdropNumber)).WillOnce(Return(6)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::checkBackdropScripts)).WillOnce(Return(5)); compiler.setBlock(block3); LooksBlocks::compileSwitchBackdropToAndWait(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndexAndWait)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToAndWait)).WillOnce(Return(4)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::backdropNumber)).WillOnce(Return(6)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::checkBackdropScripts)).WillOnce(Return(5)); compiler.setBlock(block4); LooksBlocks::compileSwitchBackdropToAndWait(&compiler); EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage)); - EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToByIndexAndWait)).WillOnce(Return(0)); + EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::switchBackdropToAndWait)).WillOnce(Return(4)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::backdropNumber)).WillOnce(Return(6)); EXPECT_CALL(m_engineMock, functionIndex(&LooksBlocks::checkBackdropScripts)).WillOnce(Return(5)); compiler.setBlock(block5); @@ -2409,14 +2420,10 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) compiler.bytecode(), std::vector( { vm::OP_START, - vm::OP_EXEC, - 6, - vm::OP_EXEC, - 5, vm::OP_CONST, 0, vm::OP_EXEC, - 0, + 4, vm::OP_EXEC, 6, vm::OP_EXEC, @@ -2432,7 +2439,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_CONST, 2, vm::OP_EXEC, - 0, + 4, vm::OP_EXEC, 6, vm::OP_EXEC, @@ -2440,7 +2447,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_CONST, 3, vm::OP_EXEC, - 0, + 4, vm::OP_EXEC, 6, vm::OP_EXEC, @@ -2448,7 +2455,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_CONST, 4, vm::OP_EXEC, - 0, + 4, vm::OP_EXEC, 6, vm::OP_EXEC, @@ -2456,6 +2463,14 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_CONST, 5, vm::OP_EXEC, + 4, + vm::OP_EXEC, + 6, + vm::OP_EXEC, + 5, + vm::OP_CONST, + 6, + vm::OP_EXEC, 0, vm::OP_EXEC, 6, @@ -2468,7 +2483,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_EXEC, 5, vm::OP_CONST, - 6, + 7, vm::OP_EXEC, 0, vm::OP_EXEC, @@ -2482,7 +2497,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_EXEC, 5, vm::OP_CONST, - 7, + 8, vm::OP_EXEC, 0, vm::OP_EXEC, @@ -2496,7 +2511,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_EXEC, 5, vm::OP_CONST, - 8, + 9, vm::OP_EXEC, 0, vm::OP_EXEC, @@ -2511,7 +2526,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWait) vm::OP_EXEC, 5, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues(), std::vector({ 1, -1, 0, 1, 3, 3, 4, 5, 6 })); + ASSERT_EQ(compiler.constValues(), std::vector({ "backdrop2", 1, "0", "1", "2", "4", 3, 4, 5, 6 })); } TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl) diff --git a/test/blocks/sound_blocks_test.cpp b/test/blocks/sound_blocks_test.cpp index d533faed..c5b2b366 100644 --- a/test/blocks/sound_blocks_test.cpp +++ b/test/blocks/sound_blocks_test.cpp @@ -172,7 +172,6 @@ TEST_F(SoundBlocksTest, Play) SoundBlocks::compilePlay(&compiler); EXPECT_CALL(m_engineMock, functionIndex(&SoundBlocks::playByIndex)).Times(0); - EXPECT_CALL(m_engineMock, functionIndex(&SoundBlocks::play)).Times(0); compiler.setBlock(block5); SoundBlocks::compilePlay(&compiler); diff --git a/test/load_project/load_project_test.cpp b/test/load_project/load_project_test.cpp index 767a5feb..827884e5 100644 --- a/test/load_project/load_project_test.cpp +++ b/test/load_project/load_project_test.cpp @@ -757,5 +757,5 @@ TEST(LoadProjectTest, LoadScientificNotationNumber) ASSERT_EQ(GET_VAR(stage, "test1")->value().toDouble(), 5000); ASSERT_VAR(stage, "test2"); - ASSERT_EQ(GET_VAR(stage, "test2")->value().toDouble(), 0); + ASSERT_EQ(GET_VAR(stage, "test2")->value().toDouble(), 4e-323); } diff --git a/test/scratch_classes/value_test.cpp b/test/scratch_classes/value_test.cpp index de214c86..9c6763c4 100644 --- a/test/scratch_classes/value_test.cpp +++ b/test/scratch_classes/value_test.cpp @@ -13,34 +13,130 @@ TEST(ValueTest, DefaultConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } TEST(ValueTest, FloatConstructor) { - Value v(3.14f); - ASSERT_EQ(v.toDouble(), 3.14f); - ASSERT_EQ(v.type(), Value::Type::Double); - ASSERT_FALSE(v.isInfinity()); - ASSERT_FALSE(v.isNegativeInfinity()); - ASSERT_FALSE(v.isNaN()); - ASSERT_TRUE(v.isNumber()); - ASSERT_FALSE(v.isBool()); - ASSERT_FALSE(v.isString()); + { + Value v(3.14f); + ASSERT_EQ(v.toDouble(), 3.14); + ASSERT_EQ(v.type(), Value::Type::Double); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isInt()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(std::numeric_limits::infinity()); + ASSERT_EQ(v.type(), Value::Type::Infinity); + ASSERT_TRUE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(-std::numeric_limits::infinity()); + ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); + ASSERT_FALSE(v.isInfinity()); + ASSERT_TRUE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(std::numeric_limits::quiet_NaN()); + ASSERT_EQ(v.type(), Value::Type::NaN); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_TRUE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } } TEST(ValueTest, DoubleConstructor) { - Value v(static_cast(3.14)); - ASSERT_EQ(v.toDouble(), 3.14); - ASSERT_EQ(v.type(), Value::Type::Double); - ASSERT_FALSE(v.isInfinity()); - ASSERT_FALSE(v.isNegativeInfinity()); - ASSERT_FALSE(v.isNaN()); - ASSERT_TRUE(v.isNumber()); - ASSERT_FALSE(v.isBool()); - ASSERT_FALSE(v.isString()); + { + Value v(static_cast(3.14)); + ASSERT_EQ(v.toDouble(), 3.14); + ASSERT_EQ(v.type(), Value::Type::Double); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isInt()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(static_cast(-5.0)); + ASSERT_EQ(v.toDouble(), -5.0); + ASSERT_EQ(v.type(), Value::Type::Double); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(std::numeric_limits::infinity()); + ASSERT_EQ(v.type(), Value::Type::Infinity); + ASSERT_TRUE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(-std::numeric_limits::infinity()); + ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); + ASSERT_FALSE(v.isInfinity()); + ASSERT_TRUE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } + + { + Value v(std::numeric_limits::quiet_NaN()); + ASSERT_EQ(v.type(), Value::Type::NaN); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_TRUE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + } } TEST(ValueTest, IntConstructor) @@ -52,6 +148,8 @@ TEST(ValueTest, IntConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -65,6 +163,8 @@ TEST(ValueTest, SizeTConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -78,6 +178,8 @@ TEST(ValueTest, LongConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -92,6 +194,8 @@ TEST(ValueTest, BoolConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_TRUE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -104,6 +208,8 @@ TEST(ValueTest, BoolConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_TRUE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -119,6 +225,8 @@ TEST(ValueTest, StdStringConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_TRUE(v.isString()); } @@ -126,31 +234,30 @@ TEST(ValueTest, StdStringConstructor) { Value v(std::string("532")); ASSERT_EQ(v.toString(), "532"); - ASSERT_EQ(v.type(), Value::Type::Integer); + ASSERT_EQ(v.type(), Value::Type::String); ASSERT_FALSE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); - ASSERT_TRUE(v.isNumber()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); - ASSERT_FALSE(v.isString()); + ASSERT_TRUE(v.isString()); } { - std::string oldLocale = std::setlocale(LC_NUMERIC, nullptr); - std::setlocale(LC_NUMERIC, "sk_SK.UTF-8"); - Value v(std::string("532.15")); - std::setlocale(LC_NUMERIC, oldLocale.c_str()); - ASSERT_EQ(v.toString(), "532.15"); - ASSERT_EQ(v.type(), Value::Type::Double); + ASSERT_EQ(v.type(), Value::Type::String); ASSERT_FALSE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); - ASSERT_TRUE(v.isNumber()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isInt()); ASSERT_FALSE(v.isBool()); - ASSERT_FALSE(v.isString()); + ASSERT_TRUE(v.isString()); } { @@ -161,42 +268,74 @@ TEST(ValueTest, StdStringConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); + ASSERT_FALSE(v.isBool()); + ASSERT_TRUE(v.isString()); + } + + { + Value v(std::string("")); + + ASSERT_EQ(v.toString(), ""); + ASSERT_EQ(v.type(), Value::Type::String); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); + ASSERT_FALSE(v.isBool()); + ASSERT_TRUE(v.isString()); + } + + { + Value v(std::string(" ")); + + ASSERT_EQ(v.toString(), " "); + ASSERT_EQ(v.type(), Value::Type::String); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_TRUE(v.isString()); } { Value v(std::string("Infinity")); - ASSERT_EQ(v.toString(), "Infinity"); ASSERT_EQ(v.type(), Value::Type::Infinity); ASSERT_TRUE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } { Value v(std::string("-Infinity")); - ASSERT_EQ(v.toString(), "-Infinity"); ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); ASSERT_FALSE(v.isInfinity()); ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } { Value v(std::string("NaN")); - ASSERT_EQ(v.toString(), "NaN"); ASSERT_EQ(v.type(), Value::Type::NaN); ASSERT_FALSE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -212,42 +351,44 @@ TEST(ValueTest, CStringConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_TRUE(v.isString()); } { Value v("Infinity"); - ASSERT_EQ(v.toString(), "Infinity"); ASSERT_EQ(v.type(), Value::Type::Infinity); ASSERT_TRUE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } { Value v("-Infinity"); - ASSERT_EQ(v.toString(), "-Infinity"); ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); ASSERT_FALSE(v.isInfinity()); ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } { Value v("NaN"); - ASSERT_EQ(v.toString(), "NaN"); ASSERT_EQ(v.type(), Value::Type::NaN); ASSERT_FALSE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -261,6 +402,8 @@ TEST(ValueTest, InfinityConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -273,6 +416,8 @@ TEST(ValueTest, NegativeInfinityConstructor) ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -285,6 +430,8 @@ TEST(ValueTest, NaNConstructor) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); + ASSERT_TRUE(v.isInt()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -300,6 +447,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_TRUE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -313,6 +461,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_TRUE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -326,6 +475,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_TRUE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -339,6 +489,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_FALSE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_TRUE(v2.isString()); } @@ -352,6 +503,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_TRUE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_FALSE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -364,6 +516,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -376,6 +529,7 @@ TEST(ValueTest, CopyConstructor) ASSERT_TRUE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -385,12 +539,43 @@ TEST(ValueTest, FloatAssignment) { Value v; v = 3.14f; - ASSERT_EQ(v.toDouble(), 3.14f); + ASSERT_EQ(v.toDouble(), 3.14); ASSERT_EQ(v.type(), Value::Type::Double); ASSERT_FALSE(v.isInfinity()); ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = std::numeric_limits::infinity(); + ASSERT_EQ(v.type(), Value::Type::Infinity); + ASSERT_TRUE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = -std::numeric_limits::infinity(); + ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); + ASSERT_FALSE(v.isInfinity()); + ASSERT_TRUE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = -std::numeric_limits::quiet_NaN(); + ASSERT_EQ(v.type(), Value::Type::NaN); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_TRUE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -405,6 +590,37 @@ TEST(ValueTest, DoubleAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = std::numeric_limits::infinity(); + ASSERT_EQ(v.type(), Value::Type::Infinity); + ASSERT_TRUE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = -std::numeric_limits::infinity(); + ASSERT_EQ(v.type(), Value::Type::NegativeInfinity); + ASSERT_FALSE(v.isInfinity()); + ASSERT_TRUE(v.isNegativeInfinity()); + ASSERT_FALSE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); + ASSERT_FALSE(v.isBool()); + ASSERT_FALSE(v.isString()); + + v = -std::numeric_limits::quiet_NaN(); + ASSERT_EQ(v.type(), Value::Type::NaN); + ASSERT_FALSE(v.isInfinity()); + ASSERT_FALSE(v.isNegativeInfinity()); + ASSERT_TRUE(v.isNaN()); + ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -419,6 +635,7 @@ TEST(ValueTest, IntAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -433,6 +650,7 @@ TEST(ValueTest, LongAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_TRUE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -448,6 +666,7 @@ TEST(ValueTest, BoolAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_TRUE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -461,6 +680,7 @@ TEST(ValueTest, BoolAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_TRUE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -477,6 +697,7 @@ TEST(ValueTest, StdStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_TRUE(v.isString()); } @@ -490,6 +711,7 @@ TEST(ValueTest, StdStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -503,6 +725,7 @@ TEST(ValueTest, StdStringAssignment) ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -516,6 +739,7 @@ TEST(ValueTest, StdStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -532,6 +756,7 @@ TEST(ValueTest, CStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_TRUE(v.isString()); } @@ -545,6 +770,7 @@ TEST(ValueTest, CStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -558,6 +784,7 @@ TEST(ValueTest, CStringAssignment) ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -571,6 +798,7 @@ TEST(ValueTest, CStringAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -585,6 +813,7 @@ TEST(ValueTest, InfinityAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -598,6 +827,7 @@ TEST(ValueTest, NegativeInfinityAssignment) ASSERT_TRUE(v.isNegativeInfinity()); ASSERT_FALSE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_TRUE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -611,6 +841,7 @@ TEST(ValueTest, NaNAssignment) ASSERT_FALSE(v.isNegativeInfinity()); ASSERT_TRUE(v.isNaN()); ASSERT_FALSE(v.isNumber()); + ASSERT_FALSE(v.isValidNumber()); ASSERT_FALSE(v.isBool()); ASSERT_FALSE(v.isString()); } @@ -627,6 +858,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_TRUE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -641,6 +873,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_TRUE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -655,6 +888,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_TRUE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -669,6 +903,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_FALSE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_TRUE(v2.isString()); } @@ -683,6 +918,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_TRUE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_FALSE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -696,6 +932,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_FALSE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -709,6 +946,7 @@ TEST(ValueTest, CopyAssignment) ASSERT_TRUE(v2.isNegativeInfinity()); ASSERT_FALSE(v2.isNaN()); ASSERT_FALSE(v2.isNumber()); + ASSERT_TRUE(v2.isValidNumber()); ASSERT_FALSE(v2.isBool()); ASSERT_FALSE(v2.isString()); } @@ -752,9 +990,9 @@ TEST(ValueTest, ToInt) ASSERT_EQ(v.toInt(), 0); // booleans represented as string shouldn't convert v = "Infinity"; - ASSERT_EQ(v.toInt(), std::numeric_limits::infinity()); + ASSERT_EQ(v.toInt(), 0); v = "-Infinity"; - ASSERT_EQ(v.toInt(), -std::numeric_limits::infinity()); + ASSERT_EQ(v.toInt(), 0); v = "NaN"; ASSERT_EQ(v.toInt(), 0); @@ -855,9 +1093,9 @@ TEST(ValueTest, ToLong) ASSERT_EQ(v.toLong(), 0); // booleans represented as string shouldn't convert v = "Infinity"; - ASSERT_EQ(v.toLong(), std::numeric_limits::infinity()); + ASSERT_EQ(v.toLong(), 0); v = "-Infinity"; - ASSERT_EQ(v.toLong(), -std::numeric_limits::infinity()); + ASSERT_EQ(v.toLong(), 0); v = "NaN"; ASSERT_EQ(v.toLong(), 0); @@ -930,12 +1168,12 @@ TEST(ValueTest, ToDouble) v = 2.54; ASSERT_EQ(v.toDouble(), 2.54); v = 2.54f; - ASSERT_EQ(v.toDouble(), 2.54f); + ASSERT_EQ(v.toDouble(), 2.54); v = -2.54; ASSERT_EQ(v.toDouble(), -2.54); v = -2.54f; - ASSERT_EQ(v.toDouble(), -2.54f); + ASSERT_EQ(v.toDouble(), -2.54); v = false; ASSERT_EQ(v.toDouble(), 0.0); @@ -968,9 +1206,9 @@ TEST(ValueTest, ToDouble) ASSERT_EQ(v.toDouble(), 0.0); // booleans represented as string shouldn't convert v = "Infinity"; - ASSERT_EQ(v.toDouble(), std::numeric_limits::infinity()); + ASSERT_TRUE(v.toDouble() > 0 && std::isinf(v.toDouble())); v = "-Infinity"; - ASSERT_EQ(v.toDouble(), -std::numeric_limits::infinity()); + ASSERT_TRUE(v.toDouble() < 0 && std::isinf(v.toDouble())); v = "NaN"; ASSERT_EQ(v.toDouble(), 0.0); @@ -1164,6 +1402,20 @@ TEST(ValueTest, ToString) ASSERT_EQ(v.toString(), "-999999999999999999"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = 2.0; + ASSERT_EQ(v.toString(), "2"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = 2.0f; + ASSERT_EQ(v.toString(), "2"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = -2.0; + ASSERT_EQ(v.toString(), "-2"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = -2.0f; + ASSERT_EQ(v.toString(), "-2"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = 2.54; ASSERT_EQ(v.toString(), "2.54"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); @@ -1178,6 +1430,45 @@ TEST(ValueTest, ToString) ASSERT_EQ(v.toString(), "-2.54"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = 2550.625021000115; + ASSERT_EQ(v.toString(), "2550.625021000115"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = 2550.625021000115f; + ASSERT_EQ(v.toString(), "2550.625"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = -2550.625021000115; + ASSERT_EQ(v.toString(), "-2550.625021000115"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = -2550.625021000115f; + ASSERT_EQ(v.toString(), "-2550.625"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = 9.4324e+20; + ASSERT_EQ(v.toString(), "943240000000000000000"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = -2.591e-2; + ASSERT_EQ(v.toString(), "-0.02591"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = 9.4324e+21; + ASSERT_EQ(v.toString(), "9.4324e+21"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = -2.591e-13; + ASSERT_EQ(v.toString(), "-2.591e-13"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + + v = 0.001; + ASSERT_EQ(v.toString(), "0.001"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = -0.001; + ASSERT_EQ(v.toString(), "-0.001"); + ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); + v = false; ASSERT_EQ(v.toString(), "false"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); @@ -1207,17 +1498,17 @@ TEST(ValueTest, ToString) ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); v = "9432.4e-12"; - ASSERT_EQ(v.toString(), "9.4324e-9"); + ASSERT_EQ(v.toString(), "9432.4e-12"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); v = "-9432.4e-12"; - ASSERT_EQ(v.toString(), "-9.4324e-9"); + ASSERT_EQ(v.toString(), "-9432.4e-12"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); v = "9432.4e+6"; - ASSERT_EQ(v.toString(), "9.4324e+9"); + ASSERT_EQ(v.toString(), "9432.4e+6"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); v = "-9432.4e+6"; - ASSERT_EQ(v.toString(), "-9.4324e+9"); + ASSERT_EQ(v.toString(), "-9432.4e+6"); ASSERT_EQ(utf8::utf16to8(v.toUtf16()), v.toString()); v = "false"; @@ -2152,6 +2443,63 @@ TEST(ValueTest, EqualityOperators) ASSERT_FALSE(v2 != v6); } + { + Value v1 = true; + Value v2 = false; + Value v3 = "00001"; + Value v4 = "00000"; + + ASSERT_TRUE(v1 == v3); + ASSERT_FALSE(v1 != v3); + + ASSERT_FALSE(v1 == v4); + ASSERT_TRUE(v1 != v4); + + ASSERT_TRUE(v2 == v4); + ASSERT_FALSE(v2 != v4); + + ASSERT_FALSE(v2 == v3); + ASSERT_TRUE(v2 != v3); + } + + { + Value v1 = "true"; + Value v2 = "false"; + Value v3 = 1; + Value v4 = 0; + + ASSERT_FALSE(v1 == v3); + ASSERT_TRUE(v1 != v3); + + ASSERT_FALSE(v1 == v4); + ASSERT_TRUE(v1 != v4); + + ASSERT_FALSE(v2 == v4); + ASSERT_TRUE(v2 != v4); + + ASSERT_FALSE(v2 == v3); + ASSERT_TRUE(v2 != v3); + } + + { + Value v1 = "true"; + Value v2 = "false"; + Value v3 = "TRUE"; + Value v4 = "FALSE"; + + ASSERT_TRUE(v1 == v3); + ASSERT_FALSE(v1 != v3); + + ASSERT_FALSE(v1 == v4); + ASSERT_TRUE(v1 != v4); + + ASSERT_TRUE(v2 == v4); + ASSERT_FALSE(v2 != v4); + + ASSERT_FALSE(v2 == v3); + ASSERT_TRUE(v2 != v3); + } + { Value v1 = true; Value v2 = false; diff --git a/test/virtual_machine/virtual_machine_test.cpp b/test/virtual_machine/virtual_machine_test.cpp index 9308116e..30ea6dbb 100644 --- a/test/virtual_machine/virtual_machine_test.cpp +++ b/test/virtual_machine/virtual_machine_test.cpp @@ -412,7 +412,11 @@ TEST(VirtualMachineTest, OP_RANDOM) static unsigned int bytecode2[] = { OP_START, OP_CONST, 1, OP_CONST, 2, OP_RANDOM, OP_HALT }; static unsigned int bytecode3[] = { OP_START, OP_CONST, 3, OP_CONST, 0, OP_RANDOM, OP_HALT }; static unsigned int bytecode4[] = { OP_START, OP_CONST, 2, OP_CONST, 3, OP_RANDOM, OP_HALT }; - static Value constValues[] = { -45, 12, 6.05, -78.686 }; + static unsigned int bytecode5[] = { OP_START, OP_CONST, 4, OP_CONST, 5, OP_RANDOM, OP_HALT }; + static unsigned int bytecode6[] = { OP_START, OP_CONST, 5, OP_CONST, 6, OP_RANDOM, OP_HALT }; + static unsigned int bytecode7[] = { OP_START, OP_CONST, 7, OP_CONST, 4, OP_RANDOM, OP_HALT }; + static unsigned int bytecode8[] = { OP_START, OP_CONST, 6, OP_CONST, 7, OP_RANDOM, OP_HALT }; + static Value constValues[] = { -45, 12, 6.05, -78.686, "-45", "12", "6.05", "-78.686" }; VirtualMachinePrivate vm(nullptr, nullptr, nullptr, nullptr); vm.constValues = constValues; @@ -455,6 +459,42 @@ TEST(VirtualMachineTest, OP_RANDOM) ASSERT_EQ(vm.regCount, 1); ASSERT_EQ(vm.regs[vm.regCount - 1]->toDouble(), -28.648764); + + EXPECT_CALL(rng, randint(-45, 12)).WillOnce(Return(-18)); + vm.bytecode = bytecode5; + vm.pos = bytecode5; + vm.regCount = 0; + vm.run(vm.pos); + + ASSERT_EQ(vm.regCount, 1); + ASSERT_EQ(vm.regs[vm.regCount - 1]->toDouble(), -18); + + EXPECT_CALL(rng, randintDouble(12, 6.05)).WillOnce(Return(3.486789)); + vm.bytecode = bytecode6; + vm.pos = bytecode6; + vm.regCount = 0; + vm.run(vm.pos); + + ASSERT_EQ(vm.regCount, 1); + ASSERT_EQ(vm.regs[vm.regCount - 1]->toDouble(), 3.486789); + + EXPECT_CALL(rng, randintDouble(-78.686, -45)).WillOnce(Return(-59.468873)); + vm.bytecode = bytecode7; + vm.pos = bytecode7; + vm.regCount = 0; + vm.run(vm.pos); + + ASSERT_EQ(vm.regCount, 1); + ASSERT_EQ(vm.regs[vm.regCount - 1]->toDouble(), -59.468873); + + EXPECT_CALL(rng, randintDouble(6.05, -78.686)).WillOnce(Return(-28.648764)); + vm.bytecode = bytecode8; + vm.pos = bytecode8; + vm.regCount = 0; + vm.run(vm.pos); + + ASSERT_EQ(vm.regCount, 1); + ASSERT_EQ(vm.regs[vm.regCount - 1]->toDouble(), -28.648764); } TEST(VirtualMachineTest, OP_ROUND) @@ -955,7 +995,7 @@ TEST(VirtualMachineTest, OP_LIST_DEL) 0, OP_CONST, 9, OP_LIST_DEL, 0, OP_READ_LIST, 0, OP_CONST, 10, OP_LIST_DEL, 0, OP_READ_LIST, 0, OP_CONST, 11, OP_LIST_DEL, 0, OP_READ_LIST, 0, OP_CONST, 12, OP_LIST_DEL, 0, OP_READ_LIST, 0, OP_CONST, 13, OP_LIST_DEL, 0, OP_READ_LIST, 0, OP_HALT }; - static Value constValues[] = { 3, 1, 6, 0, 7, -1, 9, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "invalid", "last", "random", "all" }; + static Value constValues[] = { 3, 1, "6", 0, 7, -1, 9, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "invalid", "last", "random", "all" }; List list1("", "list1"); list1.push_back("a"); list1.push_back("b"); @@ -1027,7 +1067,7 @@ TEST(VirtualMachineTest, OP_LIST_INSERT) 0, OP_CONST, 0, OP_CONST, 10, OP_LIST_INSERT, 0, OP_READ_LIST, 0, OP_CONST, 0, OP_CONST, 11, OP_LIST_INSERT, 0, OP_READ_LIST, 0, OP_CONST, 0, OP_CONST, 12, OP_LIST_INSERT, 0, OP_READ_LIST, 0, OP_CONST, 0, OP_CONST, 13, OP_LIST_INSERT, 0, OP_READ_LIST, 0, OP_HALT }; - static Value constValues[] = { "new item", 3, 1, 10, 0, 12, -1, 14, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid" }; + static Value constValues[] = { "new item", "3", 1, 10, 0, 12, -1, 14, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid" }; List list1("", "list1"); list1.push_back("a"); list1.push_back("b"); @@ -1079,7 +1119,7 @@ TEST(VirtualMachineTest, OP_LIST_REPLACE) 12, OP_CONST, 14, OP_LIST_REPLACE, 0, OP_READ_LIST, 0, OP_CONST, 13, OP_CONST, 0, OP_LIST_REPLACE, 0, OP_READ_LIST, 0, OP_HALT }; static Value constValues[] = { - "new item", 3, 1, 8, 0, 9, -1, 12, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid", "test" + "new item", 3, "1", 8, 0, 9, -1, 12, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid", "test" }; List list1("", "list1"); list1.push_back("a"); @@ -1128,7 +1168,7 @@ TEST(VirtualMachineTest, OP_LIST_GET_ITEM) 0, OP_CONST, 5, OP_LIST_GET_ITEM, 0, OP_CONST, 6, OP_LIST_GET_ITEM, 0, OP_CONST, 7, OP_LIST_GET_ITEM, 0, OP_CONST, 8, OP_LIST_GET_ITEM, 0, OP_CONST, 9, OP_LIST_GET_ITEM, 0, OP_CONST, 10, OP_LIST_GET_ITEM, 0, OP_CONST, 11, OP_LIST_GET_ITEM, 0, OP_CONST, 12, OP_LIST_GET_ITEM, 0, OP_HALT }; - static Value constValues[] = { 3, 1, 8, 0, 9, -1, 12, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid" }; + static Value constValues[] = { 3, 1, "8", 0, 9, -1, 12, Value::SpecialValue::NegativeInfinity, Value::SpecialValue::Infinity, Value::SpecialValue::NaN, "last", "random", "invalid" }; List list1("", "list1"); list1.push_back("a"); list1.push_back("b");