|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
| 4 | +using System.Reflection; |
4 | 5 |
|
5 | 6 | using NUnit.Framework; |
6 | 7 |
|
@@ -104,7 +105,130 @@ public string JoinToString(string thisIsAStringParameter, |
104 | 105 | return string.Join("-", thisIsAStringParameter, thisIsACharParameter, thisIsAnIntParameter, thisIsAFloatParameter, |
105 | 106 | thisIsADoubleParameter, thisIsADecimalParameter ?? 123.456m, thisIsABoolParameter, string.Format("{0:MMddyyyy}", thisIsADateTimeParameter)); |
106 | 107 | } |
107 | | - } |
| 108 | + |
| 109 | + public static Action StaticReadonlyActionProperty { get; } = () => Throw(); |
| 110 | + public static Action<int> StaticReadonlyActionWithParamsProperty { get; } = (i) => Throw(); |
| 111 | + public static Func<int> StaticReadonlyFuncProperty { get; } = () => |
| 112 | + { |
| 113 | + Throw(); |
| 114 | + return 42; |
| 115 | + }; |
| 116 | + public static Func<int, int> StaticReadonlyFuncWithParamsProperty { get; } = (i) => |
| 117 | + { |
| 118 | + Throw(); |
| 119 | + return i * 2; |
| 120 | + }; |
| 121 | + |
| 122 | + public static Action StaticReadonlyExpressionBodiedActionProperty => () => Throw(); |
| 123 | + public static Action<int> StaticReadonlyExpressionBodiedActionWithParamsProperty => (i) => Throw(); |
| 124 | + public static Func<int> StaticReadonlyExpressionBodiedFuncProperty => () => |
| 125 | + { |
| 126 | + Throw(); |
| 127 | + return 42; |
| 128 | + }; |
| 129 | + public static Func<int, int> StaticReadonlyExpressionBodiedFuncWithParamsProperty => (i) => |
| 130 | + { |
| 131 | + Throw(); |
| 132 | + return i * 2; |
| 133 | + }; |
| 134 | + |
| 135 | + public static readonly Action StaticReadonlyActionField = () => Throw(); |
| 136 | + public static readonly Action<int> StaticReadonlyActionWithParamsField = (i) => Throw(); |
| 137 | + public static readonly Func<int> StaticReadonlyFuncField = () => |
| 138 | + { |
| 139 | + Throw(); |
| 140 | + return 42; |
| 141 | + }; |
| 142 | + public static readonly Func<int, int> StaticReadonlyFuncWithParamsField = (i) => |
| 143 | + { |
| 144 | + Throw(); |
| 145 | + return i * 2; |
| 146 | + }; |
| 147 | + |
| 148 | + public static readonly Action StaticReadonlyExpressionBodiedActionField = () => Throw(); |
| 149 | + public static readonly Action<int> StaticReadonlyExpressionBodiedActionWithParamsField = (i) => Throw(); |
| 150 | + public static readonly Func<int> StaticReadonlyExpressionBodiedFuncField = () => |
| 151 | + { |
| 152 | + Throw(); |
| 153 | + return 42; |
| 154 | + }; |
| 155 | + public static readonly Func<int, int> StaticReadonlyExpressionBodiedFuncWithParamsField = (i) => |
| 156 | + { |
| 157 | + Throw(); |
| 158 | + return i * 2; |
| 159 | + }; |
| 160 | + |
| 161 | + private static void Throw() => throw new Exception("Pepe"); |
| 162 | + } |
| 163 | + |
| 164 | + [TestCase("StaticReadonlyActionProperty", "static_readonly_action_property", new object[] { })] |
| 165 | + [TestCase("StaticReadonlyActionWithParamsProperty", "static_readonly_action_with_params_property", new object[] { 42 })] |
| 166 | + [TestCase("StaticReadonlyFuncProperty", "static_readonly_func_property", new object[] { })] |
| 167 | + [TestCase("StaticReadonlyFuncWithParamsProperty", "static_readonly_func_with_params_property", new object[] { 42 })] |
| 168 | + [TestCase("StaticReadonlyExpressionBodiedActionProperty", "static_readonly_expression_bodied_action_property", new object[] { })] |
| 169 | + [TestCase("StaticReadonlyExpressionBodiedActionWithParamsProperty", "static_readonly_expression_bodied_action_with_params_property", new object[] { 42 })] |
| 170 | + [TestCase("StaticReadonlyExpressionBodiedFuncProperty", "static_readonly_expression_bodied_func_property", new object[] { })] |
| 171 | + [TestCase("StaticReadonlyExpressionBodiedFuncWithParamsProperty", "static_readonly_expression_bodied_func_with_params_property", new object[] { 42 })] |
| 172 | + [TestCase("StaticReadonlyActionField", "static_readonly_action_field", new object[] { })] |
| 173 | + [TestCase("StaticReadonlyActionWithParamsField", "static_readonly_action_with_params_field", new object[] { 42 })] |
| 174 | + [TestCase("StaticReadonlyFuncField", "static_readonly_func_field", new object[] { })] |
| 175 | + [TestCase("StaticReadonlyFuncWithParamsField", "static_readonly_func_with_params_field", new object[] { 42 })] |
| 176 | + [TestCase("StaticReadonlyExpressionBodiedActionField", "static_readonly_expression_bodied_action_field", new object[] { })] |
| 177 | + [TestCase("StaticReadonlyExpressionBodiedActionWithParamsField", "static_readonly_expression_bodied_action_with_params_field", new object[] { 42 })] |
| 178 | + [TestCase("StaticReadonlyExpressionBodiedFuncField", "static_readonly_expression_bodied_func_field", new object[] { })] |
| 179 | + [TestCase("StaticReadonlyExpressionBodiedFuncWithParamsField", "static_readonly_expression_bodied_func_with_params_field", new object[] { 42 })] |
| 180 | + public void StaticReadonlyCallableFieldsAndPropertiesAreBothUpperAndLowerCased(string propertyName, string snakeCasedName, object[] args) |
| 181 | + { |
| 182 | + using var obj = new SnakeCaseNamesTesClass().ToPython(); |
| 183 | + |
| 184 | + var lowerCasedName = snakeCasedName.ToLowerInvariant(); |
| 185 | + var upperCasedName = snakeCasedName.ToUpperInvariant(); |
| 186 | + |
| 187 | + var memberInfo = typeof(SnakeCaseNamesTesClass).GetMember(propertyName).First(); |
| 188 | + var callableType = memberInfo switch |
| 189 | + { |
| 190 | + PropertyInfo propertyInfo => propertyInfo.PropertyType, |
| 191 | + FieldInfo fieldInfo => fieldInfo.FieldType, |
| 192 | + _ => throw new InvalidOperationException() |
| 193 | + }; |
| 194 | + |
| 195 | + var property = obj.GetAttr(propertyName).AsManagedObject(callableType); |
| 196 | + var lowerCasedProperty = obj.GetAttr(lowerCasedName).AsManagedObject(callableType); |
| 197 | + var upperCasedProperty = obj.GetAttr(upperCasedName).AsManagedObject(callableType); |
| 198 | + |
| 199 | + Assert.IsNotNull(property); |
| 200 | + Assert.IsNotNull(property as MulticastDelegate); |
| 201 | + Assert.AreSame(property, lowerCasedProperty); |
| 202 | + Assert.AreSame(property, upperCasedProperty); |
| 203 | + |
| 204 | + var call = () => |
| 205 | + { |
| 206 | + try |
| 207 | + { |
| 208 | + (property as Delegate).DynamicInvoke(args); |
| 209 | + } |
| 210 | + catch (TargetInvocationException e) |
| 211 | + { |
| 212 | + throw e.InnerException; |
| 213 | + } |
| 214 | + }; |
| 215 | + |
| 216 | + var exception = Assert.Throws<Exception>(() => call()); |
| 217 | + Assert.AreEqual("Pepe", exception.Message); |
| 218 | + } |
| 219 | + |
| 220 | + [TestCase("PublicStaticReadonlyStringField", "public_static_readonly_string_field")] |
| 221 | + [TestCase("PublicStaticReadonlyStringGetterOnlyProperty", "public_static_readonly_string_getter_only_property")] |
| 222 | + public void NonCallableStaticReadonlyFieldsAndPropertiesAreOnlyUpperCased(string propertyName, string snakeCasedName) |
| 223 | + { |
| 224 | + using var obj = new SnakeCaseNamesTesClass().ToPython(); |
| 225 | + var lowerCasedName = snakeCasedName.ToLowerInvariant(); |
| 226 | + var upperCasedName = snakeCasedName.ToUpperInvariant(); |
| 227 | + |
| 228 | + Assert.IsTrue(obj.HasAttr(propertyName)); |
| 229 | + Assert.IsTrue(obj.HasAttr(upperCasedName)); |
| 230 | + Assert.IsFalse(obj.HasAttr(lowerCasedName)); |
| 231 | + } |
108 | 232 |
|
109 | 233 | [TestCase("AddNumbersAndGetHalf", "add_numbers_and_get_half")] |
110 | 234 | [TestCase("AddNumbersAndGetHalf_Static", "add_numbers_and_get_half_static")] |
@@ -528,6 +652,9 @@ def SetEnumValue3SnakeCase(obj): |
528 | 652 |
|
529 | 653 | private class AlreadyDefinedSnakeCaseMemberTestBaseClass |
530 | 654 | { |
| 655 | + private int private_field = 123; |
| 656 | + public int PrivateField = 333; |
| 657 | + |
531 | 658 | public virtual int SomeIntProperty { get; set; } = 123; |
532 | 659 |
|
533 | 660 | public int some_int_property { get; set; } = 321; |
@@ -593,6 +720,14 @@ public void DoesntBindSnakeCasedMemberIfAlreadyOriginallyDefinedAsMethodInBaseCl |
593 | 720 | Assert.AreEqual(654, method.Invoke().As<int>()); |
594 | 721 | } |
595 | 722 |
|
| 723 | + [Test] |
| 724 | + public void BindsMemberWithSnakeCasedNameMatchingExistingPrivateMember() |
| 725 | + { |
| 726 | + using var obj = new AlreadyDefinedSnakeCaseMemberTestBaseClass().ToPython(); |
| 727 | + |
| 728 | + Assert.AreEqual(333, obj.GetAttr("private_field").As<int>()); |
| 729 | + } |
| 730 | + |
596 | 731 | private abstract class AlreadyDefinedSnakeCaseMemberTestBaseAbstractClass |
597 | 732 | { |
598 | 733 | public abstract int AbstractProperty { get; } |
|
0 commit comments