From 1b45b8df136f6716526e66209c5a809e1dd2046a Mon Sep 17 00:00:00 2001 From: stakx Date: Sun, 4 Nov 2018 21:40:22 +0100 Subject: [PATCH] Check `IsSpecialName` for properties & indexers This is a follow-up to #712 and #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. --- src/Moq/Extensions.cs | 8 +-- tests/Moq.Tests.ComTypes/ComTypes.idl | 14 ++++ .../Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll | Bin 6656 -> 7168 bytes .../HasAbstractIndexer.fs | 10 +++ .../HasAbstractProperty.fs | 10 +++ tests/Moq.Tests.FSharpTypes/HasIndexer.fs | 11 +++ tests/Moq.Tests.FSharpTypes/HasProperty.fs | 11 +++ tests/Moq.Tests.FSharpTypes/IHasIndexer.fs | 9 +++ tests/Moq.Tests.FSharpTypes/IHasProperty.fs | 9 +++ .../Moq.Tests.FSharpTypes.fsproj | 6 ++ tests/Moq.Tests/ComCompatibilityFixture.cs | 46 ++++++++++++ tests/Moq.Tests/FSharpCompatibilityFixture.cs | 66 ++++++++++++++++++ 12 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs create mode 100644 tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs create mode 100644 tests/Moq.Tests.FSharpTypes/HasIndexer.fs create mode 100644 tests/Moq.Tests.FSharpTypes/HasProperty.fs create mode 100644 tests/Moq.Tests.FSharpTypes/IHasIndexer.fs create mode 100644 tests/Moq.Tests.FSharpTypes/IHasProperty.fs diff --git a/src/Moq/Extensions.cs b/src/Moq/Extensions.cs index eca7de58c..02f0c9bc3 100644 --- a/src/Moq/Extensions.cs +++ b/src/Moq/Extensions.cs @@ -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 diff --git a/tests/Moq.Tests.ComTypes/ComTypes.idl b/tests/Moq.Tests.ComTypes/ComTypes.idl index 09df48101..2ce881dc3 100644 --- a/tests/Moq.Tests.ComTypes/ComTypes.idl +++ b/tests/Moq.Tests.ComTypes/ComTypes.idl @@ -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); + } } diff --git a/tests/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll b/tests/Moq.Tests.ComTypes/Moq.Tests.ComTypes.dll index bbabf770d4db3c9956dd849b533faa2482fca538..9fb45f2348bd2cfac302898a5ca0b5c61ee1b363 100644 GIT binary patch delta 2466 zcmZuz3v5$W82-;a_uk&MbZgf=*w&4X@)$zL*t3=J7#(HRDF_lX=X4v4u`n6ZPMxU5 zAu6JV8A zuU;SCa^Lvf*MHhVBkeQNN?pQ5lmmr1tSqS-+*__yUpaVYQs&7@qRUx5muRdUEcMx? zqAkM*MF2g=zF$lgdG7sTC_%VjSLzyk?5G)&eLuYZu=pvQWV%nw4s_z zBIkt+qIHr;@67^B77~eUkxjjx5u2IJhw2Uk9_*U%+Hc6>+U#^B>o0|#*jR=XW&&AF zXP!$XX0w^ZhLE(^XM6PtKJ3sr=@U0XtZ5l4D%Wn*rxssKsUs%x?nugY%zE?eEqcJj zLYzsbeNYdGvG#|0NqNEORaomZcEtvqWmmOqM!6W^3stL zJ;(mu|9@cH-BcCck_4-uDi+51fgWKKez$^vulNUGMm|K9u#`d*0_4bRK?c?$*uM zzy6lfb~z@cu-V|9L=R)!jjaZkB-eJY?n>~&!%ox*V{qvbnhP1%f`SW{#v3p$0#D-V z1n2eic7St34LsN6AC!D0=#Pn2l!rrrI1U}x8+Y;FJI;A=3Y6kQ!n_>(pUw`f;{@D^ z9@K|NlTOjM_)y$}aiYR1g_kL85go#$ZYAHP@L`2}6dqFep~5dkM+&arC}L@x&aZKB zxsqoqT%vHf(yvi?r*@xa(hhAO@U+r=r0|^5{HBpK$tyWeq2!$7l{^v1+Zf)2!1yE% z)ZSt(O0jSo;Uj=DL#gi_VJ;Hzx4{Zv!_@`broJCB=*cnr=b`v9v$aymW64X=WX{2 zS)vN5rgsm>$%JczhQ+uC_@V#F(T(CvyzwHOEOQ%ukyWg99T_T;5GsBQc( z*Gu^7Fn;(8_wdk!haG9RU&1h0kn&t$VqqXvV4yKmsmn;1>J%_d|g zjloU!pkIYTHOYnK1x`b8SS|%#O%dR=6bH6Zv(mQ%SI|ws9_j}sX%n!727&!FgHn9# zM?g}vhkW`*-0u>76TJkDlRlzK-KJM5tZ#>Aj{YPxQT-Xnjd~$)Kt4~O(_;Na$jy2Q zJUf72(JK9AWNVU#=zF>y{!^%hYGgV2XtOA%B6u|mRqcoFRw4;#60jE+NSVfDq^UCwQijty;Tv7_o z797DMnk}P(vqi;JO2xG{Ot(_5S9q9?(sB9#uY$m#^BXW-@+-k;L6@O){gMm3T~?wT z5*iC#gVm{629Qgqt0L;KxKK=i@)^)Np*JDJz8ztuBCOHC0pp|-L<9IlU4h8n{2YeLmEvAWQ_d3CW+ZEd)| zt~y#1uB(pVcZgpw(MH4}HS_1ssEt%aLec7IU8p+J5DkUH72#0jj7UWtvNTl9t5+fF ltLJ+DhW}9MmdSsR0?h1!e4nV=|3`L~fx$cWJ26<{_y>cVuDSpK delta 1901 zcmYjSeQZ=k5TD(B_xkRG-bb(H+FqNx9#klJaFnk?P(%5uqC)Bg5v$mSv|yoXFGVcS zDs2M9V9zCzQ_zqa4TMm&K*T7fDp*k?DpWwlB8lQ33K~cZrs!|?de}|&w==(;nVp%p z@4fb!?Nht9mNYCHSV6;Mka*b1oJ2klW|}OHCHF`915=XcOSAhY6ICnvE~0=)hI3?? zt+abVgfM+_JDb4#@(8<)1>^-5$&G=l84U(cL!2cN?7WFPOJ<|1<3 zv=g-oBBN;(w8Us4=3_o;${yY`6Mj&eY_L$K&2D*26ixSJJQY6+JgLobD8OuX033Nv z9awFf2^55&OvJ zAXB#D|C3NI74?|_!%3XBg$mP2pslW31!hi`ZZpX8n}Y*>C_~vnguv+RBr_;$ z%ut&f-O*JS!lbOLWy$f;Kc736f4<-Nrff~a7rVD!Z$33}vE+81dh_Y5+`-b6f<_m|vpL}T4n7haKHB>*p{P7uQufO{1(S^V9WZgs2ROco8-16FsXV=WywKygJ zedOA_N%8q5M?8O>+T64Dz0=EDc5c}HPRBou?sdz4@7Q>9kI^&#rIy2?fOKY+wxPVp zW}=-~14^z=JhggVeX~mZfQ9FTH4?9;LlE$kD6%kKH4p12(Emo$BXb*@YN4wE)w3)w zPpB(FH^!Dz9-07A^+9pytB#>!q637>Me2OzsAoo2PHF;;^lH+(bOtZSHH|K&HfLGDm)7)twvXOGaXj?m1&&`3+BE!#4VY=kK(Q-3B5Eg&J(5lceKcmbsk z+^97%9Q1(J7>(7I{o%A_I+>LvX)S$1BBC^PLKrcFuWNMym1)PuF=^9st;sHjzs({S z8sov7k2%DrkQX=u4O4O$IEN~Ll~e_+qUD-@40u0135?SQU=7894%!E-r6g?@4Rn;Y ziAG9kzK`~Z7TQbQViTDCqJ#SApx8#KHtH2SKz$%yq|fMt*ai7Zu^XlXz^~~iu@~Wn z_#1SNuEHUT=eC+fDTmer3#o%u0uKTsbe7dYz6ezE7AmJd_!fMwF9Yu($-A{>H&s#- z|ClDwG+L%EPkT0{c>&c*}D3qeAru9V)}yIwD2)zL1Fr;Fz>}&s)%e`h%?KQ zZ+XXiifkf8K|2VKH}3H*l~=rhnV^(sPyr7r7YhYiLFE_ZJd3O>;alpB7uie*A&X~a s8J6V>^-lN2xSOuxcbFO3G3m`Ov=9IBhOV diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs b/tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs new file mode 100644 index 000000000..c163c243c --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/HasAbstractIndexer.fs @@ -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; + +[] +type HasAbstractIndexer() = + abstract Item: int -> obj with get, set diff --git a/tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs b/tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs new file mode 100644 index 000000000..aaa04d5c3 --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/HasAbstractProperty.fs @@ -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; + +[] +type HasAbstractProperty() = + abstract Property: obj with get, set diff --git a/tests/Moq.Tests.FSharpTypes/HasIndexer.fs b/tests/Moq.Tests.FSharpTypes/HasIndexer.fs new file mode 100644 index 000000000..e0dd17da2 --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/HasIndexer.fs @@ -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 diff --git a/tests/Moq.Tests.FSharpTypes/HasProperty.fs b/tests/Moq.Tests.FSharpTypes/HasProperty.fs new file mode 100644 index 000000000..59d59cafc --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/HasProperty.fs @@ -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 diff --git a/tests/Moq.Tests.FSharpTypes/IHasIndexer.fs b/tests/Moq.Tests.FSharpTypes/IHasIndexer.fs new file mode 100644 index 000000000..3eb985d15 --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/IHasIndexer.fs @@ -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 diff --git a/tests/Moq.Tests.FSharpTypes/IHasProperty.fs b/tests/Moq.Tests.FSharpTypes/IHasProperty.fs new file mode 100644 index 000000000..588dd7fba --- /dev/null +++ b/tests/Moq.Tests.FSharpTypes/IHasProperty.fs @@ -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 diff --git a/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj b/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj index e53ea6ad0..9f450e3b2 100644 --- a/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj +++ b/tests/Moq.Tests.FSharpTypes/Moq.Tests.FSharpTypes.fsproj @@ -13,9 +13,15 @@ + + + + + + diff --git a/tests/Moq.Tests/ComCompatibilityFixture.cs b/tests/Moq.Tests/ComCompatibilityFixture.cs index 9d7ffe708..8e1976fbd 100644 --- a/tests/Moq.Tests/ComCompatibilityFixture.cs +++ b/tests/Moq.Tests/ComCompatibilityFixture.cs @@ -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()); + } } } diff --git a/tests/Moq.Tests/FSharpCompatibilityFixture.cs b/tests/Moq.Tests/FSharpCompatibilityFixture.cs index 185e34d06..6f28a11c1 100644 --- a/tests/Moq.Tests/FSharpCompatibilityFixture.cs +++ b/tests/Moq.Tests/FSharpCompatibilityFixture.cs @@ -77,5 +77,71 @@ public void Can_unsubscribe_from_FSharp_event() Assert.Equal(1, eventRaiseCount); } + + public static IEnumerable 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 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()); + } } }