using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Scripting.Hosting;
using IronRuby.Runtime;
using IronRuby;
using Microsoft.Scripting.Hosting.Providers;
using Microsoft.Scripting;
using IronRuby.Builtins;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Scripting.Math;
namespace Test
{
[TestClass]
public class UnitTest1
{
#region 初始化
public ScriptRuntime Runtime { get; private set; }
public RubyContext Context { get; private set; }
public ScriptEngine Engine { get; private set; }
[TestInitialize]
public void Init()
{
var setup = ScriptRuntimeSetup.ReadConfiguration();
setup.AddRubySetup();
setup.PrivateBinding = true;
Runtime = Ruby.CreateRuntime(setup);
Engine = Ruby.GetEngine(Runtime);
Context = (RubyContext)HostingHelpers.GetLanguageContext(Engine);
Engine.Execute("1");//完全初始化
}
#endregion
//ruby对象转C#对象
[TestMethod]
public void SetGlobalVariable1()
{
dynamic obj;
//字符串
obj = Engine.Execute("'123'");
Assert.AreEqual(typeof(MutableString), obj.GetType());
Assert.AreEqual("123", obj.ToString());
//浮点数
obj = Engine.Execute("2.102");
Assert.AreEqual(typeof(double), obj.GetType());
Assert.AreEqual(2.102, obj);
//整数
obj = Engine.Execute("123");
Assert.AreEqual(typeof(int), obj.GetType());
Assert.AreEqual(123, obj);
//大整数(超过Int32则返回大整数)
obj = Engine.Execute("123456789123456789");
Assert.AreEqual(typeof(BigInteger), obj.GetType());
Assert.AreEqual(123456789123456789, obj);
//数组
obj = Engine.Execute("[1,2,3]");
Assert.AreEqual(typeof(RubyArray), obj.GetType());
Assert.IsTrue(new int[] { 1, 2, 3 }.SequenceEqual((obj as RubyArray).OfType<int>().ToArray()));
}
//C#向ruby传递全局变量
[TestMethod]
public void SetGlobalVariable()
{
Context.SetGlobalVariable(null, "var1", "123");
Assert.AreEqual("123abc", Engine.Execute("$var1+'abc'").ToString());
}
//ruby引用C#程序集, 命名空间和类, 调用C#扩展函数
[TestMethod]
public void Include()
{
Context.SetGlobalVariable(null, "list", new List<int> { 1, 2, 3 });
var re = Engine.Execute(@"
load_assembly 'Microsoft.VisualStudio.TestPlatform.TestFramework' #加载程序集
include Microsoft::VisualStudio::TestTools::UnitTesting
load_assembly 'System.Core' #加载程序集
include System::Text #命名空间
using_clr_extensions System::Linq #引用扩展函数
sb1 = StringBuilder.new
sb2 = System::Text::StringBuilder.new #不使用include直接引用类
Assert.IsTrue(sb1.GetType == sb2.GetType)
Assert.AreEqual(3, $list.Max) #调用扩展函数Enumerable.Sum
");
}
static string GetGenericType1<T>()
{
return typeof(T).Name;
}
static string GetGenericType2<T1, T2, T3>()
{
return typeof(T1).Name + "," + typeof(T2).Name + "," + typeof(T3).Name;
}
//泛型相关
[TestMethod]
public void Generic()
{
Engine.Execute(@"
load_assembly 'Microsoft.VisualStudio.TestPlatform.TestFramework' #加载程序集
include Microsoft::VisualStudio::TestTools::UnitTesting
include System
#使用方括号或of方法传递泛型参数
int_list_type = System::Collections::Generic::List[Int32] #获取泛型类型(MakeGenericType)
list = int_list_type.new
list.Add 1
list.Add 2
list.Add 3
Assert.AreEqual 3,list.Count
#2种方法一样效果
Assert.AreEqual Tuple.of(Int32,Single,Double).new(1,2.1,3.2) , Tuple[Int32,Single,Double].new(1,2.1,3.2)
load_assembly 'Test'
Assert.AreEqual 'Int32,Single,Double',Test::UnitTest1.method(:GetGenericType2).of(Int32,Single,Double)[].to_s #调用泛型函数, 只能使用of
");
}
//block必须放在第一个参数
static object ReceiveBlock(BlockParam block, string arg1, string arg2)
{
//调用block
return ((dynamic)block.Proc).call(arg1, arg2);
}
static object BlockBindSelf(BlockParam block, object self)
{
//使用指定的self调用block
return RubyOps.Yield0(block.Proc, self, block);
}
//ruby block相关
[TestMethod]
public void Block()
{
Engine.Execute(@"
load_assembly 'Microsoft.VisualStudio.TestPlatform.TestFramework' #加载程序集
include Microsoft::VisualStudio::TestTools::UnitTesting
include System
load_assembly 'Test'
Assert.AreEqual '123abc',Test::UnitTest1.ReceiveBlock('123','abc'){|a,b| a + b }
Assert.AreEqual '123',Test::UnitTest1.BlockBindSelf('123'){ self }
");
}
class EventTest
{
public event EventHandler<string> OnEvent;
public void Send(string msg)
{
OnEvent?.Invoke(this, msg);
}
}
//C#事件相关
[TestMethod]
public void Event()
{
Engine.Execute(@"
load_assembly 'Microsoft.VisualStudio.TestPlatform.TestFramework' #加载程序集
include Microsoft::VisualStudio::TestTools::UnitTesting
load_assembly 'Test'
ev = Test::UnitTest1::EventTest.new #内部类使用双冒号来引用
ev.OnEvent {
|sender, msg|
$msg = msg
}
ev.Send '123'
Assert.AreEqual '123',$msg
");
}
//ruby实现c#接口
[TestMethod]
public void Interface()
{
ICloneable obj = Engine.Execute(@"
class A
include System::ICloneable
def Clone
self
end
end
A.new
");
Assert.AreEqual(obj, obj.Clone());
}
public interface ISpeaker
{
string Speak();
}
public class Speaker : ISpeaker
{
public string Speak()
{
return "hello";
}
}
//open class/interface
[TestMethod]
public void MyTestMethod()
{
Context.SetGlobalVariable(null, "speaker", new Speaker());
Engine.Execute(@"
load_assembly 'Microsoft.VisualStudio.TestPlatform.TestFramework' #加载程序集
include Microsoft::VisualStudio::TestTools::UnitTesting
load_assembly 'Test'
module Test::UnitTest1::ISpeaker #为接口添加扩展方法(仅支持在ruby中调用)
def interface_speak
self.Speak+', ISpeaker'
end
end
class Test::UnitTest1::Speaker #为类添加扩展方法(仅支持在ruby中调用)
def class_speak
self.Speak+', Speaker'
end
end
Assert.AreEqual 'hello, Speaker', $speaker.class_speak
Assert.AreEqual 'hello, ISpeaker', $speaker.interface_speak
");
}
}
}