diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 20878f044..acbcacab3 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -1399,6 +1399,8 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) { throw new Exception("unsupported type:System.Decimal."); } + if (_type.FullName.Contains("Neo.SmartContract.Framework.Map") && _type.FullName.Contains(" @@ -48,8 +49,8 @@ public static class Helper /// /// Converts byte[] to string. Examples: [0x68656c6c6f] -> "hello"; [] -> ""; [0x4e656f] -> "Neo" /// - [Script] - public extern static string AsString(this byte[] source); + [OpCode(OpCode.CONVERT, StackItemType_ByteString)] + public extern static string ToByteString(this byte[] source); /// /// Returns true iff a <= x && x < b. Examples: x=5 a=5 b=15 is true; x=15 a=5 b=15 is false diff --git a/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs new file mode 100644 index 000000000..b22cb5620 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs @@ -0,0 +1,137 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests +{ + [TestClass] + public class MapTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Map.cs"); + } + + [TestMethod] + public void TestByteArrayMap() + { + Assert.ThrowsException(() => _engine.AddEntryScript("./TestClasses/Contract_MapException.cs")); + } + + [TestMethod] + public void TestByteArray() + { + _engine.Reset(); + StackItem key = System.Text.Encoding.ASCII.GetBytes("a"); + var result = _engine.ExecuteTestCaseStandard("testByteArray", key); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"a":"teststring2"} + Assert.AreEqual("7b2261223a2274657374737472696e6732227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestByteArray2() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testByteArray2"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u0001\u0001":"\u0022\u0022"} + Assert.AreEqual("7b225c75303030315c7530303031223a225c75303032325c7530303232227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicode() + { + _engine.Reset(); + StackItem key = System.Text.Encoding.UTF8.GetBytes("中"); + var result = _engine.ExecuteTestCaseStandard("testUnicode", key); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u4E2D":"129840test10022939"} + Assert.AreEqual("7b225c7534453244223a22313239383430746573743130303232393339227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicodeValue() + { + _engine.Reset(); + StackItem value = System.Text.Encoding.UTF8.GetBytes("文"); + var result = _engine.ExecuteTestCaseStandard("testUnicodeValue", value); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"ab":"\u6587"} + Assert.AreEqual("7b226162223a225c7536353837227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicodeKeyValue() + { + _engine.Reset(); + StackItem key = System.Text.Encoding.UTF8.GetBytes("中"); + StackItem value = System.Text.Encoding.UTF8.GetBytes("文"); + var result = _engine.ExecuteTestCaseStandard("testUnicodeKeyValue", key, value); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u4E2D":"\u6587"} + Assert.AreEqual("7b225c7534453244223a225c7536353837227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestInt() + { + _engine.Reset(); + StackItem key = 1; + _engine.ExecuteTestCaseStandard("testInt", key); + // Int cannot be used as the key for serializing Map + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void TestBool() + { + _engine.Reset(); + StackItem key = true; + _engine.ExecuteTestCaseStandard("testBool", key); + // Bool cannot be used as the key for serializing Map + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void TestDeserialize() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testDeserialize", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Map)); + var map = item as Map; + Assert.AreEqual(1, map.Count); + Assert.IsTrue(map.ContainsKey("a")); + Assert.AreEqual((ByteString)"testdeserialize", map["a"]); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs index 062ddaca7..85ba41092 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs @@ -19,10 +19,10 @@ public void Init() } [TestMethod] - public void TestNext() + public void TestNextIntArray() { _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testNext", new Array(new StackItem[] { 1, 2, 3 })); + var result = _engine.ExecuteTestCaseStandard("testNextIntArray", new Array(new StackItem[] { 1, 2, 3 })); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -32,12 +32,25 @@ public void TestNext() } [TestMethod] - public void TestConcat() + public void TestNextByteArray() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testNextByteArray", new byte[] { 1, 2, 3 }); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetInteger()); + } + + [TestMethod] + public void TestConcatIntArray() { // A and B _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testConcat", + var result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(new StackItem[] { 1, 2, 3 }), new Array(new StackItem[] { 4, 5, 6 }) ); @@ -51,7 +64,7 @@ public void TestConcat() // Only A _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(new StackItem[] { 1, 2, 3 }), new Array() ); @@ -65,7 +78,7 @@ public void TestConcat() // Only B _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array(new StackItem[] { 4, 5, 6 }) ); @@ -79,7 +92,7 @@ public void TestConcat() // Empty _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array() ); @@ -91,6 +104,66 @@ public void TestConcat() Assert.AreEqual(0, item.GetSpan().Length); } + [TestMethod] + public void TestConcatByteArray() + { + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { 1, 2, 3 }, + new byte[] { 4, 5, 6 } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(21, item.GetInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { 1, 2, 3 }, + new byte[] { } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { }, + new byte[] { 4, 5, 6 } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(15, item.GetInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { }, + new byte[] { } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetSpan().Length); + } + [TestMethod] public void TestIntEnumerator() { diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs index 2ec4d1e70..c9ecbf41e 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs @@ -18,10 +18,10 @@ public void Init() } [TestMethod] - public void TestNextArray() + public void TestNextIntArray() { _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testNextArray", new Array(new StackItem[] { 1, 2, 3 })); + var result = _engine.ExecuteTestCaseStandard("testNextIntArray", new Array(new StackItem[] { 1, 2, 3 })); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -31,7 +31,20 @@ public void TestNextArray() } [TestMethod] - public void TestConcatArray() + public void TestNextByteArray() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testNextByteArray", new byte[] { 1, 2, 3 }); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetInteger()); + } + + [TestMethod] + public void TestConcatIntArray() { var a = new Array(new StackItem[] { 1, 2, 3 }); var b = new Array(new StackItem[] { 4, 5, 6 }); @@ -39,7 +52,58 @@ public void TestConcatArray() // A and B _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testConcatArray", a, b); + var result = _engine.ExecuteTestCaseStandard("testConcatIntArray", a, b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(21, item.GetInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", a, new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(15, item.GetInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetSpan().Length); + } + + [TestMethod] + public void TestConcatByteArray() + { + var a = new byte[] { 1, 2, 3 }; + var b = new byte[] { 4, 5, 6 }; + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testConcatByteArray", a, b); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -50,7 +114,7 @@ public void TestConcatArray() // Only A _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", a, new Array()); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", a, new byte[] { }); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -61,7 +125,7 @@ public void TestConcatArray() // Only B _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", new Array(), b); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", new byte[] { }, b); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -72,7 +136,7 @@ public void TestConcatArray() // Empty _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", new Array(), new Array()); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", new byte[] { }, new byte[] { }); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs index 9fb156c72..fafd6befd 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs @@ -4,7 +4,7 @@ namespace Neo.Compiler.MSIL.TestClasses { public class Contract_Enumerator : SmartContract.Framework.SmartContract { - public static int TestNext(byte[] a) + public static int TestNextByteArray(byte[] a) { int sum = 0; var enumerator = Enumerator.Create(a); @@ -17,7 +17,20 @@ public static int TestNext(byte[] a) return sum; } - public static int TestConcat(byte[] a, byte[] b) + public static int TestNextIntArray(int[] a) + { + int sum = 0; + var enumerator = Enumerator.Create(a); + + while (enumerator.Next()) + { + sum += enumerator.Value; + } + + return sum; + } + + public static int TestConcatByteArray(byte[] a, byte[] b) { int sum = 0; var enumeratorA = Enumerator.Create(a); @@ -32,6 +45,21 @@ public static int TestConcat(byte[] a, byte[] b) return sum; } + public static int TestConcatIntArray(int[] a, int[] b) + { + int sum = 0; + var enumeratorA = Enumerator.Create(a); + var enumeratorB = Enumerator.Create(b); + var enumeratorC = enumeratorA.Concat(enumeratorB); + + while (enumeratorC.Next()) + { + sum += enumeratorC.Value; + } + + return sum; + } + public static Enumerator TestIntEnumerator() { var enumerator = Enumerator.Create(new int[3] { 4, 6, 8 }); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs index 3f38f045e..43b4cb28a 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs @@ -5,7 +5,7 @@ namespace Neo.Compiler.MSIL.TestClasses { public class Contract_Iterator : SmartContract.Framework.SmartContract { - public static int TestNextArray(byte[] a) + public static int TestNextByteArray(byte[] a) { int sum = 0; var iterator = Iterator.Create(a); @@ -18,7 +18,20 @@ public static int TestNextArray(byte[] a) return sum; } - public static int TestConcatArray(byte[] a, byte[] b) + public static int TestNextIntArray(int[] a) + { + int sum = 0; + var iterator = Iterator.Create(a); + + while (iterator.Next()) + { + sum += iterator.Value; + } + + return sum; + } + + public static int TestConcatByteArray(byte[] a, byte[] b) { int sum = 0; var iteratorA = Iterator.Create(a); @@ -33,6 +46,21 @@ public static int TestConcatArray(byte[] a, byte[] b) return sum; } + public static int TestConcatIntArray(int[] a, int[] b) + { + int sum = 0; + var iteratorA = Iterator.Create(a); + var iteratorB = Iterator.Create(b); + var iteratorC = iteratorA.Concat(iteratorB); + + while (iteratorC.Next()) + { + sum += iteratorC.Value; + } + + return sum; + } + public static int TestConcatMap(Map a, Map b) { int sum = 0; diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs new file mode 100644 index 000000000..2a55f713c --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.SmartContract.Framework.UnitTests.TestClasses +{ + public class Contract_Map : SmartContract + { + public static object TestByteArray(byte[] key) + { + Map some = new Map(); + some[key.ToByteString()] = "teststring2"; + return Json.Serialize(some); + } + + public static string TestByteArray2() + { + Map some = new Map(); + string key = new byte[] { 0x01, 0x01 }.ToByteString(); + some[key] = Json.Serialize(""); + return Json.Serialize(some); + } + + public static string TestUnicode(string key) + { + Map some = new Map(); + some[key] = "129840test10022939"; + return Json.Serialize(some); + } + + public static string TestUnicodeValue(string value) + { + Map some = new Map(); + some["ab"] = value; + return Json.Serialize(some); + } + + public static string TestUnicodeKeyValue(string key, string value) + { + Map some = new Map(); + some[key] = value; + return Json.Serialize(some); + } + + public static string TestInt(int key) + { + Map some = new Map(); + some[key] = "string"; + return Json.Serialize(some); + } + + public static string TestBool(bool key) + { + Map some = new Map(); + some[key] = "testbool"; + return Json.Serialize(some); + } + + public static object TestDeserialize(string key) + { + Map some = new Map(); + some[key] = "testdeserialize"; + string sea = Json.Serialize(some); + return Json.Deserialize(sea); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs new file mode 100644 index 000000000..733c51f06 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.SmartContract.Framework.UnitTests.TestClasses +{ + public class Contract_MapException : SmartContract + { + public static string TestByteArrayMap() + { + Map some = new Map(); + some[new byte[] { 0x01, 0x01 }] = Json.Serialize(""); + return Json.Serialize(some); + } + } +}