mirror of
https://github.com/PetroProtsyk/SSharp
synced 2026-06-08 12:11:10 +00:00
666 lines
16 KiB
C#
666 lines
16 KiB
C#
using System;
|
|
using System.Text;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using Scripting.SSharp.Runtime;
|
|
using Scripting.SSharp.Runtime.Promotion;
|
|
using Scripting.SSharp;
|
|
using Scripting.SSharp.Runtime.Operators;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace UnitTests
|
|
{
|
|
/// <summary>
|
|
/// Summary description for Bugs_June
|
|
/// </summary>
|
|
[TestClass]
|
|
public class BugsJune
|
|
{
|
|
[TestInitialize]
|
|
public void Setup()
|
|
{
|
|
RuntimeHost.Initialize();
|
|
EventBroker.ClearAllSubscriptions();
|
|
}
|
|
|
|
[TestCleanup]
|
|
public void TearDown()
|
|
{
|
|
RuntimeHost.CleanUp();
|
|
EventBroker.ClearAllSubscriptions();
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ExpandoFields()
|
|
{
|
|
RuntimeHost.AddType("Array", typeof(List<int>));
|
|
|
|
object resultVal =
|
|
Script.RunCode(
|
|
@"
|
|
return [
|
|
storage -> new Array(),
|
|
storage1 -> new Array(),
|
|
storage2 -> new Array()
|
|
];
|
|
"
|
|
);
|
|
|
|
Expando data = (Expando)resultVal;
|
|
|
|
Assert.IsInstanceOfType(data["storage"], typeof(List<int>));
|
|
Assert.IsInstanceOfType(data["storage1"], typeof(List<int>));
|
|
Assert.IsInstanceOfType(data["storage2"], typeof(List<int>));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestTypeExpr()
|
|
{
|
|
RuntimeHost.AddType("Int", typeof(int));
|
|
ScriptContext context = new ScriptContext();
|
|
|
|
object rez = Script.RunCode("a = 2; return a is Int;", context);
|
|
Assert.IsTrue((bool)rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestTypeExprGenerics()
|
|
{
|
|
RuntimeHost.AddType("Int", typeof(int));
|
|
ScriptContext context = new ScriptContext();
|
|
|
|
object rez = Script.RunCode("a = new List<|Int|>(); return a is List<|Int|>;", context);
|
|
Assert.IsTrue((bool)rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestTypeExprBug()
|
|
{
|
|
object rez = Script.RunCode("a = 2; return a is int;");
|
|
Assert.IsTrue((bool)rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MethodInvocationBug()
|
|
{
|
|
RuntimeHost.AddType("TestOverloading", typeof(TestOverloading));
|
|
object rez = Script.RunCode("b = new TestOverloading(); return b.GetString(2);");
|
|
Assert.AreEqual("Ok", rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestTypeExprGenerics1()
|
|
{
|
|
object rez = Script.RunCode("b = new System.Collections.Generic.Stack<|string|>();");
|
|
Assert.IsInstanceOfType(rez, typeof(Stack<string>));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void InternalClassTest()
|
|
{
|
|
object rez = Script.RunCode("Class123.Class234.Value;");
|
|
Assert.AreEqual(Class123.Class234.Value, rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TypeConversionConflictsWithArithmeticOperations()
|
|
{
|
|
object rez = Script.RunCode("(1+2+3)-6;");
|
|
Assert.AreEqual(0, rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void InterfaceLimitations()
|
|
{
|
|
object rez = Script.RunCode(@"
|
|
a = new AT1();
|
|
|
|
it = a.Method();
|
|
|
|
a.SetMethod(it);
|
|
a.Property = it;
|
|
|
|
it.Value = 2;
|
|
return it.Value;
|
|
");
|
|
|
|
Assert.AreEqual(2, rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void EqualityOperator()
|
|
{
|
|
object rez = Script.RunCode(@"
|
|
a = new Class1_1();
|
|
if (a.Short == 1 && a.C == 'C')
|
|
return 1;
|
|
else
|
|
return 2;
|
|
");
|
|
|
|
Assert.AreEqual(1, rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void EventsCrashed()
|
|
{
|
|
RuntimeHost.SetSettingItem("UnsubscribeAllEvents", false);
|
|
RuntimeHost.SetSettingItem("ContextEnabledEvents", true);
|
|
|
|
EventsCrashedTest rez = Script.RunCode(@"
|
|
|
|
a = new EventsCrashedTest();
|
|
a.Opened += myhandler;
|
|
|
|
a.State = false;
|
|
a.Open();
|
|
|
|
function myhandler(sender,e){ sender.State = true; }
|
|
|
|
return a;
|
|
") as EventsCrashedTest;
|
|
|
|
Assert.IsTrue(rez.State);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void EqualityOperatorFullTest()
|
|
{
|
|
EqualsOperator eq = new EqualsOperator();
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Byte.Parse("1"), Single.Parse("1")));
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int16.Parse("1"), Single.Parse("1")));
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int32.Parse("1"), Single.Parse("1")));
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Int64.Parse("1"), Single.Parse("1")));
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Double.Parse("1"), Single.Parse("1")));
|
|
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Byte.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Int16.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Int32.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Int64.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Double.Parse("1")));
|
|
Assert.IsTrue((bool)eq.Evaluate(Single.Parse("1"), Single.Parse("1")));
|
|
|
|
//Assert.IsTrue((bool)eq.Evaluate("C", 'C'));
|
|
|
|
}
|
|
|
|
[TestMethod]
|
|
public void OperatorOverloaderTest()
|
|
{
|
|
object rez = Script.RunCode(@"
|
|
a = new OperatorOverloader(3);
|
|
b = new OperatorOverloader(4);
|
|
c = 3.2;
|
|
|
|
return a+b;
|
|
");
|
|
|
|
Assert.AreEqual((double)7.0, ((OperatorOverloader)rez).Value);
|
|
|
|
rez = Script.RunCode(@"
|
|
a = new OperatorOverloader(3);
|
|
b = new OperatorOverloader(4);
|
|
c = 3.2;
|
|
|
|
return a+c;
|
|
");
|
|
|
|
Assert.AreEqual((double)6.2, rez);
|
|
|
|
rez = Script.RunCode(@"
|
|
a = new OperatorOverloader(3);
|
|
b = new OperatorOverloader(4);
|
|
c = 3.2;
|
|
|
|
return c+b;
|
|
");
|
|
|
|
Assert.AreEqual((double)7.2, rez);
|
|
|
|
}
|
|
|
|
[TestMethod]
|
|
public void OperatorOverloaderTest_Full()
|
|
{
|
|
object rez = Script.RunCode(@"
|
|
a = new OperatorOverloader(3);
|
|
b = new OperatorOverloader(4);
|
|
c = 3.2;
|
|
|
|
a+b;
|
|
a+c;
|
|
c+a;
|
|
a+b+c;
|
|
a+c+b;
|
|
b+c+a;
|
|
|
|
a-b;
|
|
a-c;
|
|
c-a;
|
|
a-b-c;
|
|
a-c-b;
|
|
b-c-a;
|
|
|
|
a*b;
|
|
a*c;
|
|
c*a;
|
|
a*b*c;
|
|
a*c*b;
|
|
b*c*a;
|
|
|
|
a/b;
|
|
a/c;
|
|
c/a;
|
|
a/b/c;
|
|
a/c/b;
|
|
b/c/a;
|
|
|
|
a%b;
|
|
a%c;
|
|
c%a;
|
|
a%b%c;
|
|
a%c%b;
|
|
b%c%a;
|
|
|
|
a+b*c;
|
|
a+c/b;
|
|
");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void OperatorOverloader_List()
|
|
{
|
|
object rez = Script.RunCode(@"
|
|
a = [new OperatorOverloader(3),
|
|
new OperatorOverloader(4),
|
|
new OperatorOverloader(5),
|
|
1.0];
|
|
s = 0;
|
|
|
|
for(i = 0; i < a.Length; i++)
|
|
{
|
|
s = s + a[i]*a[i];
|
|
}
|
|
|
|
return s;
|
|
");
|
|
|
|
Assert.AreEqual((double)(3*3+4*4+5*5+1*1), rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void Function_OverloadsWithConflictingTypes()
|
|
{
|
|
RuntimeHost.AddType("TestTypeConversion", typeof(TestTypeConversion));
|
|
|
|
object rez = Script.RunCode(@"
|
|
x=true; y =1; return TestTypeConversion.WriteLine('Value of x {0} and y {1}',x,y);
|
|
");
|
|
|
|
Assert.AreEqual("Value of x True and y 1", rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ContextSwitching()
|
|
{
|
|
Script s = Script.Compile("return A;");
|
|
|
|
ScriptContext sc = new ScriptContext();
|
|
sc.SetItem("A", 1);
|
|
s.Context = sc;
|
|
|
|
Assert.AreEqual(1, s.Execute());
|
|
|
|
sc = new ScriptContext();
|
|
sc.SetItem("A", 10);
|
|
s.Context = sc;
|
|
|
|
Assert.AreEqual(10, s.Execute());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void MultiDimArrays() {
|
|
object rez = Script.RunCode(@"
|
|
a = new int[3,3];
|
|
c = 1;
|
|
for (i=0; i<3; i++)
|
|
for (j=0; j<3; j++){
|
|
a[i,j] = c; c++;
|
|
}
|
|
|
|
s = '';
|
|
for (i=0; i<3; i++)
|
|
for (j=0; j<3; j++)
|
|
s += a[i,j];
|
|
|
|
return s;
|
|
");
|
|
Assert.AreEqual("123456789",rez);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ProblemWithGlobalScope()
|
|
{
|
|
Script s = Script.Compile(@"
|
|
abc = '123';
|
|
function OnGetCustomersCompleted(s, e)
|
|
{
|
|
s.v = abc;
|
|
}
|
|
|
|
s = new CustomerFacade();
|
|
s.GetCustomersCompleted += OnGetCustomersCompleted;
|
|
s.GetCustomersAsync();
|
|
|
|
return s;
|
|
");
|
|
|
|
CustomerFacade rez = (CustomerFacade)s.Execute();
|
|
|
|
while (rez.busy) System.Threading.Thread.Sleep(100);
|
|
|
|
Assert.AreEqual("123", rez.v);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ProblemWithGlobalScopeWithAsyncEvents()
|
|
{
|
|
CustomerFacade rez = (CustomerFacade)Script.RunCode(@"
|
|
abc = '123';
|
|
function OnGetCustomersCompleted(s, e)
|
|
{
|
|
s.v = abc;
|
|
}
|
|
|
|
s = new CustomerFacade();
|
|
s.GetCustomersCompleted += OnGetCustomersCompleted;
|
|
s.GetCustomersAsync();
|
|
|
|
return s;
|
|
");
|
|
|
|
//Now scope is clear, while event is still subscribed and will be invoked
|
|
while (rez.busy) System.Threading.Thread.Sleep(100);
|
|
Assert.IsTrue(rez.v.Contains("given handler is not associated with any context"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ContextReusageProblem()
|
|
{
|
|
var context = new ScriptContext();
|
|
|
|
string code1 = "'test';";
|
|
string code2 = "3*5; return 1+1;";
|
|
|
|
var result1 = Script.RunCode(code1, context, true);
|
|
|
|
var script = Script.Compile(code2);
|
|
script.Context = context;
|
|
|
|
script.Execute();
|
|
|
|
Assert.AreEqual(2, context.Result);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ContextReusageProblemMetaOperator()
|
|
{
|
|
string code1 = "a=<! return 1+2; !>; a(); 3*5; return 1+1;";
|
|
var s = Script.Compile(code1);
|
|
var c = s.Code(s.Ast);
|
|
|
|
Assert.AreEqual(2, s.Execute());
|
|
}
|
|
}
|
|
|
|
#region Interfaces
|
|
public interface IT1
|
|
{
|
|
int Value { get; set; }
|
|
}
|
|
|
|
public class AT1 : IT1
|
|
{
|
|
#region IT1 Members
|
|
|
|
public int Value
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public IT1 Method()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
public void SetMethod(IT1 v)
|
|
{
|
|
}
|
|
|
|
public IT1 Property
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Test Class
|
|
public class CustomerFacade {
|
|
|
|
public event EventHandler<EventArgs> GetCustomersCompleted;
|
|
|
|
public string v { get; set; }
|
|
|
|
public bool busy { get; set; }
|
|
|
|
public void GetCustomersAsync()
|
|
{
|
|
busy = true;
|
|
|
|
Task t = Task.Factory.StartNew(
|
|
() => {
|
|
System.Threading.Thread.Sleep(500);
|
|
|
|
try {
|
|
if (GetCustomersCompleted != null) {
|
|
GetCustomersCompleted.Invoke(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
v = e.ToString();
|
|
}
|
|
finally {
|
|
busy = false;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public class Class1_1
|
|
{
|
|
public short Short { get { return 1; } }
|
|
|
|
public char C { get { return 'C'; } }
|
|
}
|
|
|
|
public class Class123
|
|
{
|
|
public class Class234
|
|
{
|
|
public static string Value = "Test";
|
|
|
|
public string Instance = "Test1";
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Helpers
|
|
public class OperatorOverloader
|
|
{
|
|
public double Value { get; set; }
|
|
|
|
public OperatorOverloader(double value)
|
|
{
|
|
Value = value;
|
|
}
|
|
|
|
public static double operator +(OperatorOverloader oper, double k)
|
|
{
|
|
return k + oper.Value;
|
|
}
|
|
public static double operator +(double k, OperatorOverloader oper)
|
|
{
|
|
return k + oper.Value;
|
|
}
|
|
public static OperatorOverloader operator +(OperatorOverloader a, OperatorOverloader b)
|
|
{
|
|
return new OperatorOverloader( a.Value + b.Value );
|
|
}
|
|
|
|
|
|
public static double operator -(OperatorOverloader oper, double k)
|
|
{
|
|
return k - oper.Value;
|
|
}
|
|
public static double operator -(double k, OperatorOverloader oper)
|
|
{
|
|
return k - oper.Value;
|
|
}
|
|
public static OperatorOverloader operator -(OperatorOverloader a, OperatorOverloader b)
|
|
{
|
|
return new OperatorOverloader(a.Value - b.Value);
|
|
}
|
|
|
|
public static double operator *(OperatorOverloader oper, double k)
|
|
{
|
|
return k * oper.Value;
|
|
}
|
|
public static double operator *(double k, OperatorOverloader oper)
|
|
{
|
|
return k * oper.Value;
|
|
}
|
|
public static OperatorOverloader operator *(OperatorOverloader a, OperatorOverloader b)
|
|
{
|
|
return new OperatorOverloader(a.Value * b.Value);
|
|
}
|
|
|
|
public static double operator /(OperatorOverloader oper, double k)
|
|
{
|
|
return k / oper.Value;
|
|
}
|
|
public static double operator /(double k, OperatorOverloader oper)
|
|
{
|
|
return k / oper.Value;
|
|
}
|
|
public static OperatorOverloader operator /(OperatorOverloader a, OperatorOverloader b)
|
|
{
|
|
return new OperatorOverloader(a.Value / b.Value);
|
|
}
|
|
|
|
public static double operator %(OperatorOverloader oper, double k)
|
|
{
|
|
return k % oper.Value;
|
|
}
|
|
public static double operator %(double k, OperatorOverloader oper)
|
|
{
|
|
return k % oper.Value;
|
|
}
|
|
public static OperatorOverloader operator %(OperatorOverloader a, OperatorOverloader b)
|
|
{
|
|
return new OperatorOverloader(a.Value + b.Value);
|
|
}
|
|
}
|
|
|
|
class TestTypeConversion
|
|
{
|
|
public static string WriteLine(char[] format, object arg1, object arg2)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public static string WriteLine(char[] format, int arg1, int arg2)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public static string WriteLine(string format, params object[] args)
|
|
{
|
|
return string.Format(format, args);
|
|
}
|
|
|
|
public static string WriteLine(string format,object arg1, object arg2)
|
|
{
|
|
return string.Format(format, arg1, arg2);
|
|
}
|
|
}
|
|
|
|
class TestOverloading
|
|
{
|
|
public string GetString(bool value)
|
|
{
|
|
return "Error";
|
|
}
|
|
|
|
public string GetString(int value)
|
|
{
|
|
return "Ok";
|
|
}
|
|
}
|
|
|
|
public class EventsCrashedTest
|
|
{
|
|
public event EventHandler<EventArgs> Opened;
|
|
|
|
protected virtual void OnOpened()
|
|
{
|
|
if (Opened != null)
|
|
Opened.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
public void Open()
|
|
{
|
|
OnOpened();
|
|
}
|
|
|
|
public bool State { get; set; }
|
|
}
|
|
#endregion
|
|
}
|