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

Regex: add couple of regex methods to the devpack #796

Merged
merged 14 commits into from
Feb 26, 2024
109 changes: 109 additions & 0 deletions src/Neo.SmartContract.Framework/ByteString.Extension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using Neo.SmartContract.Framework.Native;
namespace Neo.SmartContract.Framework;

public static class ByteStringExtension
{
/// <summary>
/// Denotes whether provided character is a number.
/// </summary>
/// <param name="byteString">Input to check</param>
/// <returns>True if is number</returns>
public static bool IsNumber(this ByteString byteString)
Copy link
Member

Choose a reason for hiding this comment

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

It's also work for "string" type? (it could be in a different pr)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what? anything can work for string as well. But the problem is some methods string does not support some string does.

Type system in neo is a mess. That is why i suggested to use neo type only.

Copy link
Member

Choose a reason for hiding this comment

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

Type system in neo is a mess.

We need to fix this in a future, but force users to use c# with other types is worst

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to fix this in a future, but force users to use c# with other types is worst

I dont agree, C# still is not a smart contract language, forcing it to work for smart contract without any restriction is impraactical and misleading. For me, having a determinastic type system is far more importand than having a system that sometimes work sometimes dont work and you have to teach them when it works and when it does not work.

Again, worst is having a system that sometimes it works, sometimes it does not work.

{
foreach (var value in byteString)
{
if (value is < 48 or > 57)
return false;
}
return true;
}

/// <summary>
/// Denotes whether provided character is a lowercase letter.
/// </summary>
/// <param name="byteString">Input to check</param>
/// <returns>True if is Alpha character</returns>
public static bool IsLowerAlphabet(this ByteString byteString)
{
foreach (var value in byteString)
{
if (value is < 97 or > 122)
return false;
}
return true;
}

/// <summary>
/// Denotes whether provided character is a lowercase letter.
/// </summary>
/// <param name="byteString">Input to check</param>
/// <returns>True if is Alpha character</returns>
public static bool IsUpperAlphabet(this ByteString byteString)
{
foreach (var value in byteString)
{
if (value is < 65 or > 90)
return false;
}
return true;
}

/// <summary>
/// Denotes whether provided character is a lowercase letter.
/// </summary>
/// <param name="byteString">Input to check</param>
/// <returns>True if is Alpha character</returns>
public static bool IsAlphabet(this ByteString byteString)
{
foreach (var value in byteString)
{
if (!((value >= 65 && value <= 90) || (value >= 97 && value <= 122)))
return false;
}
return true;
}

/// <summary>
/// Returns the index of the first occurrence of a given value in an array.
/// </summary>
/// <param name="byteString">Array where to search.</param>
/// <param name="byteToFind">Array to search.</param>
/// <returns>Index where it is located or -1</returns>
public static int IndexOf(this ByteString byteString, ByteString byteToFind)
{
return StdLib.MemorySearch(byteString, byteToFind);
}

/// <summary>
/// Determines whether the beginning of this string instance matches the specified string when compared using the specified culture.
/// </summary>
/// <param name="byteString">Array where to search.</param>
/// <param name="byteToFind">Array to search.</param>
/// <returns>True if start with</returns>
public static bool StartWith(this ByteString byteString, ByteString byteToFind)
{
return StdLib.MemorySearch(byteString, byteToFind) == 0;
}

/// <summary>
/// Determines whether the end of this string instance matches a specified string.
/// </summary>
/// <param name="byteString">Array where to search.</param>
/// <param name="byteToFind">Array to search.</param>
/// <returns>True if ends with</returns>
public static bool EndsWith(this ByteString byteString, ByteString byteToFind)
{
return StdLib.MemorySearch(byteString, byteToFind) + byteToFind.Length == byteString.Length;
}

/// <summary>
/// Checks if the <see cref="ByteString"/> contains the given <see cref="ByteString"/>.
/// </summary>
/// <param name="byteString"><see cref="ByteString"/> to search.</param>
/// <param name="byteToFind"><see cref="ByteString"/> to be searched.</param>
/// <returns></returns>
public static bool Contains(this ByteString byteString, ByteString byteToFind)
Jim8y marked this conversation as resolved.
Show resolved Hide resolved
{
return StdLib.MemorySearch(byteString, byteToFind) != -1;
}
}
45 changes: 45 additions & 0 deletions tests/Neo.SmartContract.Framework.TestContracts/Contract_Regex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace Neo.SmartContract.Framework.UnitTests.TestClasses
{
public class Contract_Regex : SmartContract
{
public static bool TestStartWith()
{
return ((ByteString)"Hello World").StartWith("Hello");
}

public static int TestIndexOf()
{
return ((ByteString)"Hello World").IndexOf("o");
}

public static bool TestEndWith()
{
return ((ByteString)"Hello World").EndsWith("World");
}

public static bool TestContains()
{
return ((ByteString)"Hello World").Contains("ll");
}

public static bool TestNumberOnly()
{
return ((ByteString)"0123456789").IsNumber();
}

public static bool TestAlphabetOnly()
{
return ((ByteString)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").IsAlphabet();
}

public static bool TestLowerAlphabetOnly()
{
return ((ByteString)"abcdefghijklmnopqrstuvwxyz").IsAlphabet();
}

public static bool TestUpperAlphabetOnly()
{
return ((ByteString)"ABCDEFGHIJKLMNOPQRSTUVWXYZ").IsAlphabet();
}
}
}
82 changes: 82 additions & 0 deletions tests/Neo.SmartContract.Framework.UnitTests/RegexTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.VM.Types;
using Neo.SmartContract.TestEngine;

namespace Neo.SmartContract.Framework.UnitTests
{
[TestClass]
public class RegexTest
{
private TestEngine.TestEngine _engine;

[TestInitialize]
public void Init()
{
_engine = new TestEngine.TestEngine(snapshot: new TestDataCache());
_engine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_Regex.cs");
}

[TestMethod]
public void TestStartWith()
{
var result = _engine.ExecuteTestCaseStandard("testStartWith");
Assert.AreEqual(1, result.Count);
var item = result.Pop<Boolean>();
Assert.IsTrue(item.GetBoolean());
}

[TestMethod]
public void TestIndexOf()
{
_engine.Reset();
var result = _engine.ExecuteTestCaseStandard("testIndexOf");
Assert.AreEqual(1, result.Count);
var item = result.Pop<Integer>();
Assert.AreEqual(4, item.GetInteger());
}

[TestMethod]
public void TestEndWith()
{
var result = _engine.ExecuteTestCaseStandard("testEndWith");
Assert.AreEqual(1, result.Count);
var item = result.Pop<Boolean>();
Assert.IsTrue(item.GetBoolean());
}
[TestMethod]
public void TestContains()
{
var result = _engine.ExecuteTestCaseStandard("testContains");
Assert.AreEqual(1, result.Count);
var item = result.Pop<Boolean>();
Assert.IsTrue(item.GetBoolean());
}

[TestMethod]
public void TestNumberOnly()
{
var result = _engine.ExecuteTestCaseStandard("testNumberOnly");
Assert.AreEqual(1, result.Count);
var item = result.Pop<Boolean>();
Assert.IsTrue(item.GetBoolean());
}

[TestMethod]
public void TestAlphabetOnly()
{
var result = _engine.ExecuteTestCaseStandard("testAlphabetOnly");
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Pop<Boolean>().GetBoolean());

_engine.Reset();
result = _engine.ExecuteTestCaseStandard("testLowerAlphabetOnly");
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Pop<Boolean>().GetBoolean());

_engine.Reset();
result = _engine.ExecuteTestCaseStandard("testUpperAlphabetOnly");
Assert.AreEqual(1, result.Count);
Assert.IsTrue(result.Pop<Boolean>().GetBoolean());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Neo.VM;
using Neo.VM.Types;
using System;
using Neo.Persistence;
using Neo.SmartContract.TestEngine;
using Array = Neo.VM.Types.Array;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Neo.SmartContract.Template.UnitTests.templates.neocontractowner
{
/// <summary>
/// You need to build the solution to resolve Ownable class.
/// You need to build the solution to resolve OracleRequest class.
/// </summary>
[TestClass]
public class OracleRequestTests : TestBase<OracleRequest>
Expand Down
Loading