Fixing NilBehavior

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2013-02-05 10:36:38 -08:00
parent c9404b80d6
commit 3ac520fb16
6 changed files with 106 additions and 13 deletions

View File

@@ -52,6 +52,7 @@ namespace Orchard.Tests.DisplayManagement {
Assert.That(foo.Bar, Is.EqualTo("bar"));
Assert.That(foo.Bar == null, Is.False);
}
}
public class Animal : Composite {

View File

@@ -0,0 +1,41 @@
using NUnit.Framework;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
public class NilTests {
[Test]
public void NilShouldEqualToNull() {
var nil = Nil.Instance;
Assert.That(nil == null, Is.True);
Assert.That(nil != null, Is.False);
Assert.That(nil == Nil.Instance, Is.True);
Assert.That(nil != Nil.Instance, Is.False);
}
[Test]
public void NilShouldBeRecursive() {
dynamic nil = Nil.Instance;
Assert.That(nil == null, Is.True);
Assert.That(nil.Foo == null, Is.True);
Assert.That(nil.Foo.Bar == null, Is.True);
}
[Test]
public void CallingToStringOnNilShouldReturnEmpty() {
var nil = Nil.Instance;
Assert.That(nil.ToString(), Is.EqualTo(""));
}
[Test]
public void CallingToStringOnDynamicNilShouldReturnEmpty() {
dynamic nil = Nil.Instance;
Assert.That(nil.Foo.Bar.ToString(), Is.EqualTo(""));
}
}
}

View File

@@ -71,10 +71,14 @@ namespace Orchard.Tests.DisplayManagement {
}
[Test]
public void NoneEmptyZonesShouldBeNull() {
public void NoneEmptyZonesShouldNotBeNull() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
Assert.That(foo.Header == null, Is.True);
Assert.That(foo.Header != null, Is.False);
foo.Header.Add("blah");
Assert.That(foo.Header == null, Is.False);

View File

@@ -217,6 +217,7 @@
<Compile Include="Data\StubLocator.cs" />
<Compile Include="DisplayManagement\ArgsUtility.cs" />
<Compile Include="DisplayManagement\CompositeTests.cs" />
<Compile Include="DisplayManagement\NilTests.cs" />
<Compile Include="DisplayManagement\ZoneHoldingTests.cs" />
<Compile Include="DisplayManagement\DefaultDisplayManagerTests.cs" />
<Compile Include="ContainerTestBase.cs" />

View File

@@ -12,7 +12,7 @@ namespace Orchard.DisplayManagement.Shapes {
return TryGetMemberImpl(binder.Name, out result);
}
protected bool TryGetMemberImpl(string name, out object result) {
protected virtual bool TryGetMemberImpl(string name, out object result) {
if (_props.Contains(name)) {
result = _props[name];
return true;
@@ -94,14 +94,22 @@ namespace Orchard.DisplayManagement.Shapes {
return true;
}
public static bool operator ==(Composite a, Nil b) {
return ReferenceEquals(a, b) || null == a;
}
public static bool operator !=(Composite a, Nil b) {
return !(a == b);
}
public IDictionary Properties {
get { return _props; }
}
}
public class Nil : DynamicObject {
static readonly object Singleton = new Nil();
public static object Instance { get { return Singleton; } }
static readonly Nil Singleton = new Nil();
public static Nil Instance { get { return Singleton; } }
private Nil() {
}
@@ -116,22 +124,60 @@ namespace Orchard.DisplayManagement.Shapes {
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
result = Nil.Instance;
return true;
}
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) {
switch (binder.Operation) {
case ExpressionType.Equal:
result = ReferenceEquals(arg, Nil.Instance) || arg == null;
result = ReferenceEquals(arg, Nil.Instance) || (object)arg == null;
return true;
case ExpressionType.NotEqual:
result = !ReferenceEquals(arg, Nil.Instance) && arg != null;
result = !ReferenceEquals(arg, Nil.Instance) && (object)arg != null;
return true;
}
return base.TryBinaryOperation(binder, arg, out result);
}
public static bool operator ==(Nil a, Nil b) {
return true;
}
public static bool operator !=(Nil a, Nil b) {
return false;
}
public static bool operator ==(Nil a, object b) {
return ReferenceEquals(a, b) || (object)b == null;
}
public static bool operator !=(Nil a, object b) {
return !(a == b);
}
public override bool Equals(object obj) {
if (obj == null) {
return true;
}
return ReferenceEquals(obj, Nil.Instance);
}
public override int GetHashCode() {
return 0;
}
public override bool TryConvert(ConvertBinder binder, out object result) {
result = null;
return true;
}
public override string ToString() {
return string.Empty;
}
}
}

View File

@@ -38,7 +38,7 @@ namespace Orchard.UI.Zones {
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) {
var name = binder.Name;
if (!base.TryGetMember(binder, out result) || ((dynamic)result) == null) {
if (!base.TryGetMember(binder, out result) || (null == result)) {
// substitute nil results with a robot that turns adds a zone on
// the parent when .Add is invoked
result = new ZoneOnDemand(_zoneFactory, this, name);
@@ -67,7 +67,7 @@ namespace Orchard.UI.Zones {
return TryGetMemberImpl(binder.Name, out result);
}
private bool TryGetMemberImpl(string name, out object result) {
protected override bool TryGetMemberImpl(string name, out object result) {
var parentMember = ((dynamic)_parent)[name];
if (parentMember == null) {
@@ -139,18 +139,18 @@ namespace Orchard.UI.Zones {
}
public override bool TryConvert(System.Dynamic.ConvertBinder binder, out object result) {
result = null;
result = Nil.Instance;
return true;
}
public static bool operator ==(ZoneOnDemand expr, object arg) {
public static bool operator ==(ZoneOnDemand a, object b) {
// if ZoneOnDemand is compared to null it must return true
return arg == null || ReferenceEquals(arg, Nil.Instance);
return b == null || ReferenceEquals(b, Nil.Instance);
}
public static bool operator !=(ZoneOnDemand expr, object arg) {
public static bool operator !=(ZoneOnDemand a, object b) {
// if ZoneOnDemand is compared to null it must return true
return arg != null && !ReferenceEquals(arg, Nil.Instance);
return !(a == b);
}
public override bool Equals(object obj) {