📄 resolvertests.cs
字号:
/*
* Created by SharpDevelop.
* User: Daniel Grunwald
* Date: 23.04.2006
* Time: 11:33
*/
using System;
using System.Collections;
using System.Reflection;
using NUnit.Framework;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Project;
using Grunwald.BooBinding.CodeCompletion;
namespace Grunwald.BooBinding.Tests
{
[TestFixture]
public class ResolverTests
{
#region Helper
T Resolve<T>(string code) where T : ResolveResult
{
return Resolve<T>(code, "/*1*/");
}
T Resolve<T>(string code, string marker) where T : ResolveResult
{
return Resolve<T>(normalProg, code, marker);
}
T Resolve<T>(string prog, string code, string marker) where T : ResolveResult
{
ResolveResult rr = Resolve(prog, new ExpressionResult(code), marker);
Assert.IsNotNull(rr, "Resolve must not return null");
Assert.IsInstanceOfType(typeof(T), rr, "Resolve must return instance of type " + typeof(T).Name);
return (T)rr;
}
IProjectContent booLangPC;
public ResolverTests() {
booLangPC = new ReflectionProjectContent(Assembly.Load("Boo.Lang"), "Boo.Lang.dll");
booLangPC.ReferencedContents.Add(ProjectContentRegistry.Mscorlib);
}
const string fileName = "tempFile.boo";
DefaultProjectContent lastPC;
void Register(string prog)
{
DefaultProjectContent pc = new DefaultProjectContent();
lastPC = pc;
ParserService.ForceProjectContent(pc);
pc.ReferencedContents.Add(ProjectContentRegistry.Mscorlib);
pc.ReferencedContents.Add(ProjectContentRegistry.WinForms);
pc.ReferencedContents.Add(booLangPC);
ICompilationUnit cu = new BooParser().Parse(pc, fileName, prog);
ParserService.UpdateParseInformation(cu, fileName, false, false);
cu.Classes.ForEach(pc.AddClassToNamespaceList);
}
void GetPos(string prog, string marker, out int line, out int column)
{
int index = prog.IndexOf(marker);
line = 1;
column = 0;
for (int i = 0; i < index; i++) {
column++;
if (prog[i]=='\n') {
line++;
column = 0;
}
}
}
ResolveResult Resolve(string prog, ExpressionResult er, string marker)
{
Register(prog);
int line, column;
GetPos(prog, marker, out line, out column);
BooResolver r = new BooResolver();
return r.Resolve(er, line, column, fileName, prog);
}
#endregion
#region Basic tests
const string normalProg =
"import System\n" +
"def MyMethod(arg as string):\n" +
"\tlocalVar = arg\n" +
"\t/*1*/\n" +
"\tclosure = { e as string | arg.IndexOf(e) /*inClosure*/ }\n" +
"\tindex = closure('.')\n" +
"\t/*2*/\n" +
"\tclosure2 = def(e as DateTime):\n" +
"\t\treturn e.Year\n" +
"\trecursiveClosure = def(myObject):/*inRecursiveClosure*/\n" +
"\t\treturn recursiveClosure(myObject)\n" +
"\t/*3*/\n";
[Test]
public void MethodParameter()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("arg");
Assert.IsTrue(rr.IsParameter);
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void LocalVariable()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("localVar");
Assert.IsFalse(rr.IsParameter);
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void NullCoalescing()
{
ResolveResult rr = Resolve<ResolveResult>("localVar or arg");
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void InnerClassEnum()
{
TypeResolveResult trr = Resolve<TypeResolveResult>("Environment.SpecialFolder");
Assert.AreEqual("System.Environment.SpecialFolder", trr.ResolvedClass.FullyQualifiedName);
MemberResolveResult mrr = Resolve<MemberResolveResult>("Environment.SpecialFolder.Desktop");
Assert.AreEqual("System.Environment.SpecialFolder.Desktop", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void ClosureParameter()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("e", "/*inClosure*/");
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
Assert.IsNull(Resolve(normalProg, new ExpressionResult("e"), "/*1*/"));
}
[Test]
public void ClosureCall()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("closure('.')", "/*2*/");
Assert.IsFalse(rr.IsParameter);
Assert.AreEqual("closure", rr.Field.Name);
Assert.AreEqual("System.Int32", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void ClosureCall2()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("closure2(DateTime.Now)", "/*3*/");
Assert.IsFalse(rr.IsParameter);
Assert.AreEqual("closure2", rr.Field.Name);
Assert.AreEqual("System.Int32", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void RecursiveClosure()
{
// Code-completion cannot work here, test if SharpDevelop is correctly
// preventing the StackOverflow.
LocalResolveResult rr = Resolve<LocalResolveResult>("recursiveClosure", "/*3*/");
Assert.IsFalse(rr.IsParameter);
Assert.AreEqual("delegate(myObject:Object):?", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void ClosureTypelessArgument()
{
LocalResolveResult rr = Resolve<LocalResolveResult>("myObject", "/*inRecursiveClosure*/");
Assert.AreEqual("System.Object", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void EqualityOperator()
{
ResolveResult rr = Resolve<ResolveResult>("0 == 0");
Assert.AreEqual("System.Boolean", rr.ResolvedType.FullyQualifiedName);
rr = Resolve<ResolveResult>("0 != 1");
Assert.AreEqual("System.Boolean", rr.ResolvedType.FullyQualifiedName);
rr = Resolve<ResolveResult>("null is null");
Assert.AreEqual("System.Boolean", rr.ResolvedType.FullyQualifiedName);
rr = Resolve<ResolveResult>("object() is not null");
Assert.AreEqual("System.Boolean", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void ClassMethodAmbiguity()
{
string prog =
"class Test:\n" +
"\tdef constructor():\n" +
"\t\tpass\n" +
"class OtherClass:\n" +
"\tdef Test():\n" +
"\t\t/*mark*/\n" +
"\t\tpass\n";
MemberResolveResult rr = Resolve<MemberResolveResult>(prog, "Test()", "/*mark*/");
Assert.AreEqual("OtherClass.Test", rr.ResolvedMember.FullyQualifiedName);
}
#endregion
#region Regression
const string regressionProg =
"import System\n" +
"import System.Reflection\n" +
"def MyMethod(arg as string):\n" +
"\tif true:\n" +
"\t\tboo629 = 'hello'\n" +
"\tfor boo640a in [1, 2, 3]:\n" +
"\t\tif boo640b = boo640a as FieldInfo: /*640*/\n" +
"\t\t\tprint boo640b\n" +
"\t\n" +
"\tprint 'end of method'\n" +
"\t/*1*/\n";
[Test]
public void MyMethodCompletion()
{
MethodResolveResult rr = Resolve<MethodResolveResult>(regressionProg, "MyMethod", "/*1*/");
ArrayList arr = rr.GetCompletionData(lastPC);
Assert.IsNotNull(arr);
bool beginInvoke = false;
bool invoke = false;
foreach (IMember m in arr) {
if (m.Name == "BeginInvoke") beginInvoke = true;
if (m.Name == "Invoke") invoke = true;
}
Assert.IsTrue(beginInvoke, "beginInvoke");
Assert.IsTrue(invoke, "invoke");
}
[Test]
public void Boo629VariableScope()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(regressionProg, "boo629", "/*1*/");
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
}
[Test]
public void Boo640ConditionalAssignment()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(regressionProg, "boo640b", "/*1*/");
Assert.AreEqual("System.Reflection.FieldInfo", rr.ResolvedType.FullyQualifiedName);
rr = Resolve<LocalResolveResult>(regressionProg, "boo640a", "/*640*/");
Assert.AreEqual("System.Object", rr.ResolvedType.FullyQualifiedName);
Assert.IsNull(Resolve(regressionProg, new ExpressionResult("boo640a"), "/*1*/"));
}
[Test]
public void IndexerRecognition()
{
string prog =
"class Foo:\n" +
"\tself[index as int]:\n" +
"\t\tget:\n" +
"\t\t\treturn true\n" +
"def example():\n" +
"\tfoo = Foo()\n" +
"\tmybool = foo[1] /*mark*/\n" +
"\tprint mybool\n";
MemberResolveResult rr = Resolve<MemberResolveResult>(prog, "foo[1]", "/*mark*/");
Assert.IsTrue(((IProperty)rr.ResolvedMember).IsIndexer);
Assert.AreEqual("System.Boolean", rr.ResolvedType.FullyQualifiedName);
LocalResolveResult rr2 = Resolve<LocalResolveResult>(prog, "mybool", "/*mark*/");
Assert.AreEqual("System.Boolean", rr2.ResolvedType.FullyQualifiedName);
}
[Test]
public void InfiniteRecursionGenerator()
{
string prog =
"class Test:\n" +
"\t_testList = []\n" +
"\tTestProperty:\n" +
"\t\tget:\n" +
"\t\t\tfor testobj as Test in _testList:\n" +
"\t\t\t\tyield testobj.TestProperty /*mark*/\n";
MemberResolveResult rr = Resolve<MemberResolveResult>(prog, "testobj.TestProperty", "/*mark*/");
Assert.AreEqual("Test.TestProperty", rr.ResolvedMember.FullyQualifiedName);
Assert.AreEqual("System.Collections.Generic.IEnumerable", rr.ResolvedType.FullyQualifiedName);
// prevent creating self-referring ConstructedReturnType
Assert.AreEqual("?", rr.ResolvedType.TypeArguments[0].FullyQualifiedName);
}
#endregion
#region Nested Classes
const string nestedClassProg =
"class Outer:\n" +
"\tpublic static outerField = 1\n" +
"\tpublic class Inner:\n/*inner*/" +
"\t\tpublic innerField = 2\n" +
"class Derived(Outer):\n/*derived*/" +
"\tpublic static derivedField = 3\n" +
"def Method():\n" +
"\ti as Outer.Inner\n" +
"\ti2 as Derived.Inner\n" +
"\t/*1*/";
[Test]
public void NestedClassTypeResolution()
{
TypeResolveResult trr;
trr = Resolve<TypeResolveResult>(nestedClassProg, "Outer.Inner", "/*1*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Inner", "/*inner*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Inner", "/*derived*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Derived.Inner", "/*1*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
}
[Test]
public void NestedClassCtrlSpace()
{
CtrlSpace(nestedClassProg.Replace("/*inner*/", "/*mark*/"), "outerField", "innerField", "Inner", "Outer", "Derived");
CtrlSpace(nestedClassProg.Replace("/*derived*/", "/*mark*/"), "outerField", "derivedField", "Inner", "Outer", "Derived");
}
[Test]
public void NestedClassParentStaticField()
{
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "outerField", "/*inner*/");
Assert.AreEqual("Outer.outerField", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void NestedClassCC()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(nestedClassProg, "i", "/*1*/");
Assert.AreEqual("Outer.Inner", rr.ResolvedType.FullyQualifiedName);
bool ok = false;
foreach (object o in rr.GetCompletionData(lastPC)) {
IMember m = o as IMember;
if (m != null && m.Name == "innerField")
ok = true;
}
Assert.IsTrue(ok);
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "i.innerField", "/*1*/");
Assert.AreEqual("Outer.Inner.innerField", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void NestedClassCC2()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(nestedClassProg, "i2", "/*1*/");
Assert.AreEqual("Outer.Inner", rr.ResolvedType.FullyQualifiedName);
bool ok = false;
foreach (object o in rr.GetCompletionData(lastPC)) {
IMember m = o as IMember;
if (m != null && m.Name == "innerField")
ok = true;
}
Assert.IsTrue(ok);
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "i2.innerField", "/*1*/");
Assert.AreEqual("Outer.Inner.innerField", mrr.ResolvedMember.FullyQualifiedName);
}
#endregion
#region CtrlSpace
void CtrlSpace(string prog, params string[] expected)
{
CtrlSpace(new string[0], prog, expected);
}
void CtrlSpace(string[] unExpected, string prog, params string[] expected)
{
Register(prog);
int line, column;
GetPos(prog, "/*mark*/", out line, out column);
BooResolver r = new BooResolver();
System.Collections.ArrayList ar;
ar = r.CtrlSpace(line, column, fileName, prog, ExpressionContext.Default);
foreach (string e in unExpected) {
foreach (object o in ar) {
if (e.Equals(o))
Assert.Fail("Didn't expect " + e);
if (o is IMember && (o as IMember).Name == e) {
Assert.Fail("Didn't expect " + e);
}
if (o is IClass && (o as IClass).Name == e) {
Assert.Fail("Didn't expect " + e);
}
}
}
foreach (string e in expected) {
bool ok = false;
foreach (object o in ar) {
if (e.Equals(o)) {
if (ok) Assert.Fail("double entry " + e);
ok = true;
}
if (o is IMember && (o as IMember).Name == e) {
if (ok) Assert.Fail("double entry " + e);
ok = true;
}
if (o is IClass && (o as IClass).Name == e) {
if (ok) Assert.Fail("double entry " + e);
ok = true;
}
}
if (!ok)
Assert.Fail("Expected " + e);
}
}
[Test]
public void CtrlSpaceScopeExtension()
{
string prog =
"def Foo():\n" +
"\tbar = def():\n" +
"\t\tx = 0\n" +
"\t\t/*mark*/\n";
CtrlSpace(prog, "bar", "x");
}
[Test]
public void DoubleEntryTest()
{
string prog =
"class MyClass:\n" +
"\t_myInt = 0\n" +
"\tdef Foo():\n" +
"\t\t_myInt = 5\n" +
"\t\t/*mark*/\n";
CtrlSpace(prog, "_myInt");
}
[Test]
public void LoopInClosureTest()
{
string prog =
"def Foo():\n" +
"\tfor i in range(5):\n" +
"\t\tbar = def():\n" +
"\t\t\tx = 0\n" +
"\t\t\t/*mark*/\n" +
"\t\t\tprint x";
CtrlSpace(prog, "x", "bar", "i");
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -