From 5b44c970404c964b9217446b0ef3eddd5351d4b7 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 27 Aug 2023 21:43:54 +0200
Subject: [PATCH 1/7] fix #141: Check digits when converting string to long

---
 include/scratchcpp/value.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/scratchcpp/value.h b/include/scratchcpp/value.h
index c50b8de4..5f230b7c 100644
--- a/include/scratchcpp/value.h
+++ b/include/scratchcpp/value.h
@@ -660,6 +660,14 @@ class LIBSCRATCHCPP_EXPORT Value : public ValueVariant
                 return 0;
             }
 
+            static const std::string digits = "0123456789+-";
+
+            for (char c : s) {
+                if (digits.find(c) == std::string::npos) {
+                    return 0;
+                }
+            }
+
             try {
                 if (ok)
                     *ok = true;

From 9a6c0e720aec60e3d7eccf1aa0241a73cbce504e Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 27 Aug 2023 21:44:13 +0200
Subject: [PATCH 2/7] Add test for #141

---
 test/scratch_classes/value_test.cpp | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/test/scratch_classes/value_test.cpp b/test/scratch_classes/value_test.cpp
index 2a5d14c3..bab6d681 100644
--- a/test/scratch_classes/value_test.cpp
+++ b/test/scratch_classes/value_test.cpp
@@ -123,6 +123,30 @@ TEST(ValueTest, StdStringConstructor)
         ASSERT_TRUE(v.isString());
     }
 
+    {
+        Value v(std::string("532"));
+        ASSERT_EQ(v.toString(), "532");
+        ASSERT_EQ(v.type(), Value::Type::Number);
+        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(std::string("1 2 3"));
+        ASSERT_EQ(v.toString(), "1 2 3");
+        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.isBool());
+        ASSERT_TRUE(v.isString());
+    }
+
     {
         Value v(std::string("Infinity"));
         ASSERT_EQ(v.toString(), "Infinity");

From e8c4f45cce940d357951e761b0c865aaf60d8a6f Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 9 Sep 2023 12:22:27 +0200
Subject: [PATCH 3/7] Value: Implement operator!=

---
 include/scratchcpp/value.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/scratchcpp/value.h b/include/scratchcpp/value.h
index 5f230b7c..e1860707 100644
--- a/include/scratchcpp/value.h
+++ b/include/scratchcpp/value.h
@@ -455,6 +455,8 @@ class LIBSCRATCHCPP_EXPORT Value : public ValueVariant
             return false;
         }
 
+        friend bool operator!=(const Value &v1, const Value &v2) { return !(v1 == v2); }
+
         friend bool operator>(const Value &v1, const Value &v2)
         {
             if ((static_cast<int>(v1.m_type) < 0) || (static_cast<int>(v2.m_type) < 0)) {

From e186dfcf7c923de52fea1c63147fe9d60a5017dc Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 9 Sep 2023 13:58:14 +0200
Subject: [PATCH 4/7] Add Value equality operator test

---
 test/scratch_classes/value_test.cpp | 352 ++++++++++++++++++++++++++++
 1 file changed, 352 insertions(+)

diff --git a/test/scratch_classes/value_test.cpp b/test/scratch_classes/value_test.cpp
index bab6d681..d6faa609 100644
--- a/test/scratch_classes/value_test.cpp
+++ b/test/scratch_classes/value_test.cpp
@@ -1467,3 +1467,355 @@ TEST(ValueTest, ModOperator)
     v = -150;
     ASSERT_EQ(v % "-Infinity", -150);
 }
+
+TEST(ValueTest, EqualityOperators)
+{
+    {
+        Value v1 = 10;
+        Value v2 = 10;
+        Value v3 = 8;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = -4.25;
+        Value v2 = -4.25;
+        Value v3 = 5.312;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = true;
+        Value v2 = true;
+        Value v3 = false;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = "abC def";
+        Value v2 = "abC def";
+        Value v3 = "abc dEf";
+        Value v4 = "hello world";
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_TRUE(v1 == v3);
+        ASSERT_FALSE(v1 != v3);
+
+        ASSERT_TRUE(v2 == v3);
+        ASSERT_FALSE(v2 != v3);
+
+        ASSERT_FALSE(v1 == v4);
+        ASSERT_TRUE(v1 != v4);
+
+        ASSERT_FALSE(v2 == v4);
+        ASSERT_TRUE(v2 != v4);
+
+        ASSERT_FALSE(v3 == v4);
+        ASSERT_TRUE(v3 != v4);
+    }
+
+    {
+        Value v1(Value::SpecialValue::Infinity);
+        Value v2(Value::SpecialValue::Infinity);
+        Value v3(Value::SpecialValue::NegativeInfinity);
+        Value v4(Value::SpecialValue::NegativeInfinity);
+        Value v5(Value::SpecialValue::NaN);
+        Value v6(Value::SpecialValue::NaN);
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_TRUE(v3 == v4);
+        ASSERT_FALSE(v3 != v4);
+
+        // TODO: Enable this after #196 is fixed
+        /*ASSERT_TRUE(v5 == v6);
+        ASSERT_FALSE(v5 != v6);*/
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v1 == v5);
+        ASSERT_TRUE(v1 != v5);
+
+        ASSERT_FALSE(v3 == v5);
+        ASSERT_TRUE(v3 != v5);
+    }
+
+    {
+        Value v1 = 5.00;
+        Value v2 = 5;
+        Value v3 = 6;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = 1;
+        Value v2 = true;
+        Value v3 = false;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = 5.25;
+        Value v2 = "5.25";
+        Value v3 = "5.26";
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = 1;
+        Value v2 = true;
+        Value v3 = false;
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+    }
+
+    {
+        Value v1 = 5;
+        Value v2 = 0;
+        Value v3(Value::SpecialValue::Infinity);
+        Value v4(Value::SpecialValue::NegativeInfinity);
+        Value v5(Value::SpecialValue::NaN);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v1 == v4);
+        ASSERT_TRUE(v1 != v4);
+
+        ASSERT_FALSE(v1 == v5);
+        ASSERT_TRUE(v1 != v5);
+
+        // TODO: Enable this after #198 is fixed
+        /*ASSERT_FALSE(v2 == v5);
+        ASSERT_TRUE(v2 != v5);*/
+    }
+
+    {
+        Value v1 = true;
+        Value v2 = false;
+        Value v3 = "true";
+        Value v4 = "false";
+        Value v5 = "TRUE";
+        Value v6 = "FALSE";
+
+        ASSERT_TRUE(v1 == v3);
+        ASSERT_FALSE(v1 != v3);
+
+        ASSERT_TRUE(v2 == v4);
+        ASSERT_FALSE(v2 != v4);
+
+        ASSERT_FALSE(v1 == v2);
+        ASSERT_TRUE(v1 != v2);
+
+        ASSERT_FALSE(v2 == v3);
+        ASSERT_TRUE(v2 != v3);
+
+        ASSERT_TRUE(v1 == v5);
+        ASSERT_FALSE(v1 != v5);
+
+        ASSERT_TRUE(v2 == v6);
+        ASSERT_FALSE(v2 != v6);
+    }
+
+    {
+        Value v1 = true;
+        Value v2 = false;
+        Value v3(Value::SpecialValue::Infinity);
+        Value v4(Value::SpecialValue::NegativeInfinity);
+        Value v5(Value::SpecialValue::NaN);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v1 == v4);
+        ASSERT_TRUE(v1 != v4);
+
+        ASSERT_FALSE(v1 == v5);
+        ASSERT_TRUE(v1 != v5);
+
+        ASSERT_FALSE(v2 == v5);
+        ASSERT_TRUE(v2 != v5);
+    }
+
+    {
+        Value v1 = "Infinity";
+        Value v2 = "infinity";
+        Value v3 = "-Infinity";
+        Value v4 = "-infinity";
+        Value v5 = "NaN";
+        Value v6 = "nan";
+        Value v7(Value::SpecialValue::Infinity);
+        Value v8(Value::SpecialValue::NegativeInfinity);
+        Value v9(Value::SpecialValue::NaN);
+
+        // Infinity
+        ASSERT_TRUE(v1 == v7);
+        ASSERT_FALSE(v1 != v7);
+
+        ASSERT_FALSE(v1 == v8);
+        ASSERT_TRUE(v1 != v8);
+
+        ASSERT_FALSE(v1 == v9);
+        ASSERT_TRUE(v1 != v9);
+
+        // infinity
+        ASSERT_TRUE(v2 == v7);
+        ASSERT_FALSE(v2 != v7);
+
+        ASSERT_FALSE(v2 == v8);
+        ASSERT_TRUE(v2 != v8);
+
+        ASSERT_FALSE(v2 == v9);
+        ASSERT_TRUE(v2 != v9);
+
+        // -Infinity
+        ASSERT_FALSE(v3 == v7);
+        ASSERT_TRUE(v3 != v7);
+
+        ASSERT_TRUE(v3 == v8);
+        ASSERT_FALSE(v3 != v8);
+
+        ASSERT_FALSE(v3 == v9);
+        ASSERT_TRUE(v3 != v9);
+
+        // -infinity
+        ASSERT_FALSE(v4 == v7);
+        ASSERT_TRUE(v4 != v7);
+
+        ASSERT_TRUE(v4 == v8);
+        ASSERT_FALSE(v4 != v8);
+
+        ASSERT_FALSE(v4 == v9);
+        ASSERT_TRUE(v4 != v9);
+
+        // NaN
+        ASSERT_FALSE(v5 == v7);
+        ASSERT_TRUE(v5 != v7);
+
+        ASSERT_FALSE(v5 == v8);
+        ASSERT_TRUE(v5 != v8);
+
+        // TODO: Enable this after #197 is fixed
+        /*ASSERT_TRUE(v5 == v9);
+        ASSERT_FALSE(v5 != v9);*/
+
+        // nan
+        ASSERT_FALSE(v6 == v7);
+        ASSERT_TRUE(v6 != v7);
+
+        ASSERT_FALSE(v6 == v8);
+        ASSERT_TRUE(v6 != v8);
+
+        ASSERT_TRUE(v6 == v9);
+        ASSERT_FALSE(v6 != v9);
+    }
+
+    {
+        Value v1 = "abc";
+        Value v2 = " ";
+        Value v3 = "";
+        Value v4 = "0";
+        Value v5(Value::SpecialValue::Infinity);
+        Value v6(Value::SpecialValue::NegativeInfinity);
+        Value v7(Value::SpecialValue::NaN);
+
+        // Infinity
+        ASSERT_FALSE(v1 == v5);
+        ASSERT_TRUE(v1 != v5);
+
+        ASSERT_FALSE(v2 == v5);
+        ASSERT_TRUE(v2 != v5);
+
+        ASSERT_FALSE(v3 == v5);
+        ASSERT_TRUE(v3 != v5);
+
+        ASSERT_FALSE(v4 == v5);
+        ASSERT_TRUE(v4 != v5);
+
+        // -Infinity
+        ASSERT_FALSE(v1 == v6);
+        ASSERT_TRUE(v1 != v6);
+
+        ASSERT_FALSE(v2 == v6);
+        ASSERT_TRUE(v2 != v6);
+
+        ASSERT_FALSE(v3 == v6);
+        ASSERT_TRUE(v3 != v6);
+
+        ASSERT_FALSE(v4 == v6);
+        ASSERT_TRUE(v4 != v6);
+
+        // NaN
+        ASSERT_FALSE(v1 == v7);
+        ASSERT_TRUE(v1 != v7);
+
+        ASSERT_FALSE(v2 == v7);
+        ASSERT_TRUE(v2 != v7);
+
+        ASSERT_FALSE(v3 == v7);
+        ASSERT_TRUE(v3 != v7);
+
+        // TODO: Enable this after #198 is fixed
+        /*ASSERT_FALSE(v4 == v7);
+        ASSERT_TRUE(v4 != v7);*/
+    }
+}

From dae1ae8b539ea478c3c4c84df5d7536e6487981c Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 9 Sep 2023 14:59:29 +0200
Subject: [PATCH 5/7] Fix a typo in OP_LIST_APPEND test

---
 test/virtual_machine/virtual_machine_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/virtual_machine/virtual_machine_test.cpp b/test/virtual_machine/virtual_machine_test.cpp
index aa34ec1a..8edc8771 100644
--- a/test/virtual_machine/virtual_machine_test.cpp
+++ b/test/virtual_machine/virtual_machine_test.cpp
@@ -830,7 +830,7 @@ TEST(VirtualMachineTest, OP_LIST_APPEND)
     ASSERT_EQ(list1[0], 3.52);
 
     ASSERT_EQ(list2.size(), 1);
-    ASSERT_EQ(list2[1], "test");
+    ASSERT_EQ(list2[0], "test");
 
     ASSERT_EQ(vm.registerCount(), 0);
 }

From 72fbeabb6927cb867065d2fb6f7d99e0826820a0 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 9 Sep 2023 14:59:49 +0200
Subject: [PATCH 6/7] Fix value comparison in load project test

---
 test/load_project/load_project_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/load_project/load_project_test.cpp b/test/load_project/load_project_test.cpp
index 4585ec29..c417fa67 100644
--- a/test/load_project/load_project_test.cpp
+++ b/test/load_project/load_project_test.cpp
@@ -191,7 +191,7 @@ TEST(LoadProjectTest, LoadTestProject)
         ASSERT_EQ(prototype->argumentIds().size(), 2);
         ASSERT_EQ(prototype->argumentNames(), std::vector<std::string>({ "num or text", "bool" }));
         ASSERT_EQ(prototype->argumentTypes(), std::vector<BlockPrototype::ArgType>({ BlockPrototype::ArgType::StringNum, BlockPrototype::ArgType::Bool }));
-        ASSERT_EQ(prototype->argumentDefaults(), std::vector<Value>({ 0, false }));
+        ASSERT_EQ(prototype->argumentDefaults(), std::vector<Value>({ "", false }));
         ASSERT_EQ(prototype->procCode(), "custom block %s %b");
         ASSERT_INPUT(blockPrototype, prototype->argumentIds()[0]);
         auto argBlock = GET_INPUT(blockPrototype, prototype->argumentIds()[0])->valueBlock();

From f0d5ae5a1f31356708e2d24be566eebc98a259d7 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 9 Sep 2023 14:59:59 +0200
Subject: [PATCH 7/7] fix #142: Compare strings before comparing numbers

---
 include/scratchcpp/value.h          |  6 +++---
 test/scratch_classes/value_test.cpp | 16 ++++++++++++++++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/include/scratchcpp/value.h b/include/scratchcpp/value.h
index e1860707..86925a6a 100644
--- a/include/scratchcpp/value.h
+++ b/include/scratchcpp/value.h
@@ -443,12 +443,12 @@ class LIBSCRATCHCPP_EXPORT Value : public ValueVariant
                         }
                 }
             } else {
-                if (v1.isNumber() || v2.isNumber())
+                if (v1.isString() || v2.isString())
+                    return stringsEqual(v1.toUtf16(), v2.toUtf16());
+                else if (v1.isNumber() || v2.isNumber())
                     return v1.toDouble() == v2.toDouble();
                 else if (v1.isBool() || v2.isBool())
                     return ((v1.m_type != Type::NaN && v2.m_type != Type::NaN) && (v1.toBool() == v2.toBool()));
-                else if (v1.isString() || v2.isString())
-                    return stringsEqual(v1.toUtf16(), v2.toUtf16());
                 else
                     return false;
             }
diff --git a/test/scratch_classes/value_test.cpp b/test/scratch_classes/value_test.cpp
index d6faa609..234f092b 100644
--- a/test/scratch_classes/value_test.cpp
+++ b/test/scratch_classes/value_test.cpp
@@ -1613,6 +1613,22 @@ TEST(ValueTest, EqualityOperators)
         ASSERT_TRUE(v2 != v3);
     }
 
+    {
+        Value v1 = 0;
+        Value v2 = "0";
+        Value v3 = "1";
+        Value v4 = "test";
+
+        ASSERT_TRUE(v1 == v2);
+        ASSERT_FALSE(v1 != v2);
+
+        ASSERT_FALSE(v1 == v3);
+        ASSERT_TRUE(v1 != v3);
+
+        ASSERT_FALSE(v1 == v4);
+        ASSERT_TRUE(v1 != v4);
+    }
+
     {
         Value v1 = 1;
         Value v2 = true;
