diff --git a/src/TestEngine/Engine.cs b/src/TestEngine/Engine.cs index e6d7cd34c..5c2ce13c5 100644 --- a/src/TestEngine/Engine.cs +++ b/src/TestEngine/Engine.cs @@ -1,10 +1,12 @@ using Neo.Cryptography.ECC; using Neo.IO.Json; +using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; +using System.Collections.Generic; namespace Neo.TestingEngine { @@ -48,6 +50,22 @@ public void SetTestEngine(string path) }); } + public void SetStorage(Dictionary storage) + { + foreach (var data in storage) + { + var key = new StorageKey() + { + Key = data.Key.GetSpan().ToArray() + }; + var value = new StorageItem() + { + Value = data.Value.GetSpan().ToArray() + }; + ((TestDataCache)engine.Snapshot.Storages).AddForTest(key, value); + } + } + public JObject Run(string method, StackItem[] args) { engine.GetMethod(method).RunEx(args); diff --git a/src/TestEngine/Program.cs b/src/TestEngine/Program.cs index 61a3050a8..7faee797a 100644 --- a/src/TestEngine/Program.cs +++ b/src/TestEngine/Program.cs @@ -89,7 +89,8 @@ public static JObject RunWithMethodName(string path, string methodName, string j } } - return Run(path, methodName, parameters); + var smartContractTestCase = new SmartContractTest(path, methodName, parameters); + return Run(smartContractTestCase); } catch (Exception e) { @@ -126,7 +127,13 @@ public static JObject RunWithJson(JObject json) var methodName = json["method"].AsString(); var parameters = (JArray)json["arguments"]; - return Run(path, methodName, parameters); + var smartContractTestCase = new SmartContractTest(path, methodName, parameters); + + if (json.ContainsProperty("storage")) + { + smartContractTestCase.storage = GetStorageFromJson(json["storage"]); + } + return Run(smartContractTestCase); } catch (Exception e) { @@ -141,22 +148,28 @@ public static JObject RunWithJson(JObject json) /// The name of the targeted method /// Arguments of the method /// Returns a json with the engine state after executing the script - public static JObject Run(string path, string method, JArray parameters) + public static JObject Run(SmartContractTest smartContractTest) { - if (!File.Exists(path)) + if (!File.Exists(smartContractTest.nefPath)) { return BuildJsonException("File doesn't exists"); } - if (Path.GetExtension(path).ToLowerInvariant() != ".nef") + if (Path.GetExtension(smartContractTest.nefPath).ToLowerInvariant() != ".nef") { return BuildJsonException("Invalid file. A .nef file required."); } try { - Engine.Instance.SetTestEngine(path); - var stackParams = GetStackItemParameters(parameters); - return Engine.Instance.Run(method, stackParams); + Engine.Instance.SetTestEngine(smartContractTest.nefPath); + + if (smartContractTest.storage.Count > 0) + { + Engine.Instance.SetStorage(smartContractTest.storage); + } + + var stackParams = GetStackItemParameters(smartContractTest.methodParameters); + return Engine.Instance.Run(smartContractTest.methodName, stackParams); } catch (Exception e) { @@ -164,6 +177,40 @@ public static JObject Run(string path, string method, JArray parameters) } } + /// + /// Converts the data in a json array to a dictionary of StackItem + /// + /// json array with the map values to be converted + /// Returns the built StackItem dictionary + private static Dictionary GetStorageFromJson(JObject jsonStorage) + { + if (!(jsonStorage is JArray storage)) + { + throw new Exception("Expecting an array object in 'storage'"); + } + + var missingFieldMessage = "Missing field '{0}'"; + var items = new Dictionary(); + foreach (var pair in storage) + { + if (!pair.ContainsProperty("key")) + { + throw new Exception(string.Format(missingFieldMessage, "key")); + } + + if (!pair.ContainsProperty("value")) + { + throw new Exception(string.Format(missingFieldMessage, "value")); + } + + var key = (PrimitiveType)ContractParameter.FromJson(pair["key"]).ToStackItem(); + var value = ContractParameter.FromJson(pair["value"]).ToStackItem(); + items[key] = value; + } + + return items; + } + /// /// Converts the data in a json array to an array of StackItem /// diff --git a/src/TestEngine/SmartContractTest.cs b/src/TestEngine/SmartContractTest.cs new file mode 100644 index 000000000..f7f4313b3 --- /dev/null +++ b/src/TestEngine/SmartContractTest.cs @@ -0,0 +1,22 @@ +using Neo.IO.Json; +using Neo.VM.Types; +using System.Collections.Generic; + +namespace Neo.TestingEngine +{ + public class SmartContractTest + { + public string nefPath; + public string methodName; + public JArray methodParameters; + public Dictionary storage = new Dictionary(); + + public SmartContractTest(string path, string method, JArray parameters) + { + nefPath = path; + methodName = method; + methodParameters = parameters; + storage.Clear(); + } + } +} diff --git a/src/TestEngine/TestUtils/TestDataCache.cs b/src/TestEngine/TestUtils/TestDataCache.cs index 50646312b..c561ed17f 100644 --- a/src/TestEngine/TestUtils/TestDataCache.cs +++ b/src/TestEngine/TestUtils/TestDataCache.cs @@ -62,5 +62,13 @@ public void Clear() { dic.Clear(); } + + /// + /// Include a new value to the storage for unit test + /// + public void AddForTest(TKey key, TValue value) + { + AddInternal(key, value); + } } } diff --git a/tests/TestEngine.UnitTests/UnitTest_Invoke.cs b/tests/TestEngine.UnitTests/UnitTest_Invoke.cs index 15509a255..30783cc06 100644 --- a/tests/TestEngine.UnitTests/UnitTest_Invoke.cs +++ b/tests/TestEngine.UnitTests/UnitTest_Invoke.cs @@ -3,6 +3,7 @@ using Neo.TestingEngine; using Neo.VM; using Neo.VM.Types; +using System.Collections.Generic; using System.IO; using Compiler = Neo.Compiler.Program; @@ -271,5 +272,47 @@ public void Test_Json_With_Parameters() Assert.IsTrue(resultStack[0].ContainsProperty("value")); Assert.AreEqual(resultStack[0]["value"].AsString(), wantresult.ToJson()["value"].AsString()); } + + [TestMethod] + public void Test_Json_With_Storage() + { + StackItem arguments = 16; + PrimitiveType key = "example"; + StackItem value = 123; + + Map storage = new Map() + { + [key] = value + }; + + var json = new JObject(); + json["path"] = "./TestClasses/Contract1.nef"; + json["method"] = "testArgs1"; + json["arguments"] = new JArray() { arguments.ToParameter().ToJson() }; + json["storage"] = storage.ToParameter().ToJson()["value"]; + + var args = new string[] { + json.AsString() + }; + var result = Program.Run(args); + + // search in the storage + Assert.IsTrue(result.ContainsProperty("storage")); + Assert.IsInstanceOfType(result["storage"], typeof(JArray)); + + storage[key] = value.GetSpan().ToArray(); + var storageArray = result["storage"] as JArray; + + var contains = false; + foreach (var pair in storageArray) + { + if (pair.AsString() == storage.ToJson()["value"].AsString()) + { + contains = true; + break; + } + } + Assert.IsTrue(contains); + } } }