Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add byte.AsString and Map UTs #303

Merged
merged 18 commits into from
Jul 16, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ private void ConvertLdArg(ILMethod method, OpCode src, NeoMethod to, int pos)
{
Convert1by1(VM.OpCode.LDARG, src, to, new byte[] { (byte)pos });
}

if (method.paramtypes[pos].type.FullName == "System.Byte[]")
{
Insert1(VM.OpCode.CONVERT, "", to, new byte[] { (byte)VM.Types.StackItemType.Buffer });
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we do conversion when loading argument?

Copy link
Contributor Author

@ShawnYun ShawnYun Jul 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because a byte[] should be converted to Buffer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. But you shouldn't convert it when loading. I think the conversion should be done when the data is pushed onto the stack.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, here is the opcode LDARG, arg will be pushed onto stack.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion should be done when the first time that the data is pushed onto the stack. LDARG loads the data from the slot, and the data from the slot is from stack before.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise, you have to convert it everytime when load from slot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The args appears to be pushed on the stack before Loadscript? The compiler cannot convert it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then don't convert it. The argument should be string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can check the type of agrs in INITSLOT. Now in NeoVM we only check the count, not the type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can check the type of agrs in INITSLOT.

I think it's good, it may not be efficient for compiler to check the parameter type after INITSLOT.

}

private void ConvertStArg(OpCode src, NeoMethod to, int pos)
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.4.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Neo" Version="3.0.0-CI00958" />
<PackageReference Include="Neo" Version="3.0.0-CI00959" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions src/Neo.SmartContract.Framework/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Neo.SmartContract.Framework
public static class Helper
{
internal const string StackItemType_Integer = "0x21";
internal const string StackItemType_ByteString = "0x28";
internal const string StackItemType_Buffer = "0x30";

/// <summary>
Expand Down Expand Up @@ -37,8 +38,8 @@ public static class Helper
/// <summary>
/// Converts byte[] to string. Examples: [0x68656c6c6f] -> "hello"; [] -> ""; [0x4e656f] -> "Neo"
/// </summary>
[Script]
public extern static string AsString(this byte[] source);
[OpCode(OpCode.CONVERT, StackItemType_ByteString)]
public extern static string ToByteString(this byte[] source);

/// <summary>
/// Returns true iff a <= x && x < b. Examples: x=5 a=5 b=15 is true; x=15 a=5 b=15 is false
Expand Down
139 changes: 139 additions & 0 deletions tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
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 TestByteArray()
{
_engine.Reset();
_engine.ExecuteTestCaseStandard("testByteArray");
Assert.AreEqual(VMState.FAULT, _engine.State);
}

[TestMethod]
public void TestByteArray2()
{
_engine.Reset();
StackItem key = System.Text.Encoding.ASCII.GetBytes("a");
var result = _engine.ExecuteTestCaseStandard("testByteArray2", 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 TestByteArray3()
{
_engine.Reset();
var result = _engine.ExecuteTestCaseStandard("testByteArray3");
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"]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 })
);
Expand All @@ -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()
);
Expand All @@ -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 })
);
Expand All @@ -79,7 +92,7 @@ public void TestConcat()
// Empty

_engine.Reset();
result = _engine.ExecuteTestCaseStandard("testConcat",
result = _engine.ExecuteTestCaseStandard("testConcatIntArray",
new Array(),
new Array()
);
Expand All @@ -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()
{
Expand Down
Loading