Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
Check IsSpecialName for properties & indexers
Browse files Browse the repository at this point in the history
This is a follow-up to devlooped#712 and devlooped#713, where we added tests documenting
F# and COM events not being marked with the IL `specialname` flag. But
as it turns out, F# and COM *properties and indexer* accessor methods
are marked as `specialname`, which we document here using unit tests.
Finally, we bring back checks for `method.IsSpecialName` for property
and indexer accessor method recognition.
  • Loading branch information
stakx committed Nov 4, 2018
1 parent 08c5f5f commit 1b45b8d
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/Moq/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,22 @@ public static bool IsExtensionMethod(this MethodInfo method)

public static bool IsPropertyGetter(this MethodInfo method)
{
return method.Name.StartsWith("get_", StringComparison.Ordinal);
return method.IsSpecialName && method.Name.StartsWith("get_", StringComparison.Ordinal);
}

public static bool IsPropertyIndexerGetter(this MethodInfo method)
{
return method.Name.StartsWith("get_Item", StringComparison.Ordinal);
return method.IsSpecialName && method.Name.StartsWith("get_Item", StringComparison.Ordinal);
}

public static bool IsPropertyIndexerSetter(this MethodInfo method)
{
return method.Name.StartsWith("set_Item", StringComparison.Ordinal);
return method.IsSpecialName && method.Name.StartsWith("set_Item", StringComparison.Ordinal);
}

public static bool IsPropertySetter(this MethodInfo method)
{
return method.Name.StartsWith("set_", StringComparison.Ordinal);
return method.IsSpecialName && method.Name.StartsWith("set_", StringComparison.Ordinal);
}

// NOTE: The following two methods used to first check whether `method.IsSpecialName` was set
Expand Down
14 changes: 14 additions & 0 deletions tests/Moq.Tests.ComTypes/ComTypes.idl
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,18 @@ library ComTypes
[default] interface IButton;
[default, source] interface IButtonEvents;
}

[uuid("5ee16909-c4c7-49dc-8808-219078e5d3ba")]
interface IHasIndexer : IUnknown
{
[propget, bindable, defaultbind] HRESULT Item([in] long index, [out, retval] long *value);
[propput, bindable, defaultbind] HRESULT Item([in] long index, [in] long value);
}

[uuid("62a88a92-d8e5-45f7-bb7f-668a74c58749")]
interface IHasProperty : IUnknown
{
[propget] HRESULT Property([out, retval] long *value);
[propput] HRESULT Property([in] long value);
}
}
Binary file modified tests/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll
Binary file not shown.
10 changes: 10 additions & 0 deletions tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

[<AbstractClass>]
type HasAbstractIndexer() =
abstract Item: int -> obj with get, set
10 changes: 10 additions & 0 deletions tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

[<AbstractClass>]
type HasAbstractProperty() =
abstract Property: obj with get, set
11 changes: 11 additions & 0 deletions tests/Moq.Tests.FSharpTypes/HasIndexer.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

type HasIndexer() =
let mutable item = new obj()
abstract Item: int -> obj with get, set
default this.Item with get(index: int) = item and set (index: int) (value: obj) = item <- value
11 changes: 11 additions & 0 deletions tests/Moq.Tests.FSharpTypes/HasProperty.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

type HasProperty() =
let mutable property = new obj()
abstract Property: obj with get, set
default this.Property with get() = property and set(value: obj) = property <- value
9 changes: 9 additions & 0 deletions tests/Moq.Tests.FSharpTypes/IHasIndexer.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

type IHasIndexer =
abstract member Item: int -> obj with get, set
9 changes: 9 additions & 0 deletions tests/Moq.Tests.FSharpTypes/IHasProperty.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD.
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.

namespace Moq.Tests.FSharpTypes

open System;

type IHasProperty =
abstract member Property: obj with get, set
6 changes: 6 additions & 0 deletions tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@
<ItemGroup>
<Compile Include="HasAbstractActionEvent.fs" />
<Compile Include="HasAbstractEventHandlerEvent.fs" />
<Compile Include="HasAbstractIndexer.fs" />
<Compile Include="HasAbstractProperty.fs" />
<Compile Include="HasActionEvent.fs" />
<Compile Include="HasIndexer.fs" />
<Compile Include="HasProperty.fs" />
<Compile Include="IHasActionEvent.fs" />
<Compile Include="IHasEventHandlerEvent.fs" />
<Compile Include="IHasIndexer.fs" />
<Compile Include="IHasProperty.fs" />
</ItemGroup>

<Target Name="Test" DependsOnTargets="Build" />
Expand Down
46 changes: 46 additions & 0 deletions tests/Moq.Tests/ComCompatibilityFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,52 @@ public void Can_unsubscribe_from_COM_interop_type_event()

Assert.Equal(1, eventRaiseCount);
}

[Fact]
public void COM_interop_type_property_has_accessors_that_are_marked_as_specialname()
{
var property = typeof(IHasProperty).GetProperty(nameof(IHasProperty.Property));
Assert.All(property.GetAccessors(), accessor => Assert.True(accessor.IsSpecialName, "Accessor is not marked as `specialname`."));
}

[Fact]
public void COM_interop_type_property_getter_is_recognized_as_such()
{
var property = typeof(IHasProperty).GetProperty(nameof(IHasProperty.Property));
var getter = property.GetGetMethod(true);
Assert.True(getter.IsPropertyGetter());
}

[Fact]
public void COM_interop_type_property_setter_is_recognized_as_such()
{
var property = typeof(IHasProperty).GetProperty(nameof(IHasProperty.Property));
var setter = property.GetSetMethod(true);
Assert.True(setter.IsPropertySetter());
}

[Fact]
public void COM_interop_type_indexer_has_accessors_that_are_marked_as_specialname()
{
var indexer = typeof(IHasIndexer).GetProperty(nameof(IHasIndexer.Item));
Assert.All(indexer.GetAccessors(), accessor => Assert.True(accessor.IsSpecialName, "Accessor is not marked as `specialname`."));
}

[Fact]
public void COM_interop_type_indexer_getter_is_recognized_as_such()
{
var indexer = typeof(IHasIndexer).GetProperty(nameof(IHasIndexer.Item));
var getter = indexer.GetGetMethod(true);
Assert.True(getter.IsPropertyIndexerGetter());
}

[Fact]
public void COM_interop_type_indexer_setter_is_recognized_as_such()
{
var indexer = typeof(IHasIndexer).GetProperty(nameof(IHasIndexer.Item));
var setter = indexer.GetSetMethod(true);
Assert.True(setter.IsPropertyIndexerSetter());
}
}
}

Expand Down
66 changes: 66 additions & 0 deletions tests/Moq.Tests/FSharpCompatibilityFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,71 @@ public void Can_unsubscribe_from_FSharp_event()

Assert.Equal(1, eventRaiseCount);
}

public static IEnumerable<object[]> FSharpIndexers
{
get
{
yield return new object[] { typeof(IHasIndexer).GetProperty("Item") };
yield return new object[] { typeof(HasAbstractIndexer).GetProperty("Item") };
yield return new object[] { typeof(HasIndexer).GetProperty("Item") };
}
}

[Theory]
[MemberData(nameof(FSharpIndexers))]
public void All_FSharp_indexers_have_accessors_marked_as_specialname(PropertyInfo indexer)
{
Assert.All(indexer.GetAccessors(), accessor => Assert.True(accessor.IsSpecialName, "Accessor not marked as `specialname`."));
}

[Theory]
[MemberData(nameof(FSharpIndexers))]
public void All_FSharp_indexer_getters_are_recognized_as_such(PropertyInfo indexer)
{
var getter = indexer.GetGetMethod(true);
Assert.True(getter.IsPropertyGetter());
}

[Theory]
[MemberData(nameof(FSharpIndexers))]
public void All_FSharp_indexer_setters_are_recognized_as_such(PropertyInfo indexer)
{
var setter = indexer.GetSetMethod(true);
Assert.True(setter.IsPropertySetter());
}

public static IEnumerable<object[]> FSharpProperties
{
get
{
yield return new object[] { typeof(IHasProperty).GetProperty(nameof(IHasProperty.Property)) };
yield return new object[] { typeof(HasAbstractProperty).GetProperty(nameof(HasAbstractProperty.Property)) };
yield return new object[] { typeof(HasProperty).GetProperty(nameof(HasProperty.Property)) };
}
}

[Theory]
[MemberData(nameof(FSharpProperties))]
public void All_FSharp_properties_have_accessors_marked_as_specialname(PropertyInfo property)
{
Assert.All(@property.GetAccessors(), accessor => Assert.True(accessor.IsSpecialName, "Accessor not marked as `specialname`."));
}

[Theory]
[MemberData(nameof(FSharpProperties))]
public void All_FSharp_property_getters_are_recognized_as_such(PropertyInfo property)
{
var getter = property.GetGetMethod(true);
Assert.True(getter.IsPropertyGetter());
}

[Theory]
[MemberData(nameof(FSharpProperties))]
public void All_FSharp_property_setters_are_recognized_as_such(PropertyInfo property)
{
var setter = property.GetSetMethod(true);
Assert.True(setter.IsPropertySetter());
}
}
}

0 comments on commit 1b45b8d

Please sign in to comment.