Skip to content

Commit a89295c

Browse files
committed
Fixed a error, that occurred during finding the suitable method overload, that receives numeric values and interfaces as parameters, of the host object
1 parent 47ce9db commit a89295c

File tree

10 files changed

+184
-54
lines changed

10 files changed

+184
-54
lines changed

NuGet/MsieJavaScriptEngine.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<requireLicenseAcceptance>false</requireLicenseAcceptance>
1313
<description>This library is a .NET wrapper for working with the JavaScript engines of Internet Explorer and Edge (JsRT versions of Chakra, ActiveScript version of Chakra and Classic JavaScript Engine). Project was based on the code of SassAndCoffee.JavaScript (http://github.com/paulcbetts/SassAndCoffee), Chakra Sample Hosts (http://github.com/panopticoncentral/chakra-host) and jsrt-dotnet (http://github.com/robpaveza/jsrt-dotnet).</description>
1414
<summary>This library is a .NET wrapper for working with the JavaScript engines of Internet Explorer and Edge (JsRT versions of Chakra, ActiveScript version of Chakra and Classic JavaScript Engine).</summary>
15-
<releaseNotes>Added a ability to interrupt execution of the script.</releaseNotes>
15+
<releaseNotes>Fixed a error, that occurred during finding the suitable method overload, that receives numeric values and interfaces as parameters, of the host object.</releaseNotes>
1616
<copyright>Copyright (c) 2012-2017 Andrey Taritsyn - http://www.taritsyn.ru</copyright>
1717
<language>en-US</language>
1818
<tags>JavaScript ECMAScript MSIE IE Edge Chakra</tags>

NuGet/readme.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
=============
2222
RELEASE NOTES
2323
=============
24-
Added a ability to interrupt execution of the script.
24+
Fixed a error, that occurred during finding the suitable method overload, that
25+
receives numeric values and interfaces as parameters, of the host object.
2526

2627
============
2728
PROJECT SITE

src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#if NETSTANDARD1_3
22
using System;
3+
using System.Collections.Generic;
34
using System.Linq;
45
using System.Reflection;
56

@@ -85,9 +86,8 @@ public static void FixArgumentTypes(ref object[] argValues, ParameterInfo[] para
8586

8687
public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValues)
8788
{
88-
int argCount = argValues.Length;
89-
var methodCandidates = methods
90-
.Select(m => new
89+
MethodWithMetadata[] methodCandidates = methods
90+
.Select(m => new MethodWithMetadata
9191
{
9292
Method = m,
9393
ParameterTypes = m.GetParameters()
@@ -96,12 +96,14 @@ public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValu
9696
})
9797
.ToArray()
9898
;
99-
100-
var methodsWithSameArity = methodCandidates
99+
int argCount = argValues.Length;
100+
MethodWithMetadata[] sameArityMethods = methodCandidates
101101
.Where(m => m.ParameterTypes.Length == argCount)
102102
.ToArray()
103103
;
104-
if (methodsWithSameArity.Length == 0)
104+
105+
int sameArityMethodCount = sameArityMethods.Length;
106+
if (sameArityMethodCount == 0)
105107
{
106108
return null;
107109
}
@@ -110,40 +112,46 @@ public static MethodBase GetBestFitMethod(MethodBase[] methods, object[] argValu
110112
.Select(a => a.GetType())
111113
.ToArray()
112114
;
113-
var weaklyCompatibleMethods = methodsWithSameArity
114-
.Where(m => CompareParameterTypes(argValues, argTypes, m.ParameterTypes, false))
115-
.ToArray()
116-
;
115+
var compatibleMethods = new List<MethodWithMetadata>();
117116

118-
int weaklyCompatibleMethodCount = weaklyCompatibleMethods.Length;
119-
if (weaklyCompatibleMethodCount > 0)
117+
for (int methodIndex = 0; methodIndex < sameArityMethodCount; methodIndex++)
120118
{
121-
if (weaklyCompatibleMethodCount == 1)
119+
MethodWithMetadata method = sameArityMethods[methodIndex];
120+
ushort compatibilityScore;
121+
122+
if (CompareParameterTypes(argValues, argTypes, method.ParameterTypes, out compatibilityScore))
122123
{
123-
return weaklyCompatibleMethods[0].Method;
124+
method.CompatibilityScore = compatibilityScore;
125+
compatibleMethods.Add(method);
124126
}
127+
}
125128

126-
var strictlyCompatibleMethods = weaklyCompatibleMethods
127-
.Where(m => CompareParameterTypes(argValues, argTypes, m.ParameterTypes, true))
128-
.ToArray()
129-
;
130-
if (strictlyCompatibleMethods.Length > 0)
129+
int compatibleMethodCount = compatibleMethods.Count;
130+
if (compatibleMethodCount > 0)
131+
{
132+
if (compatibleMethodCount == 1)
131133
{
132-
return strictlyCompatibleMethods[0].Method;
134+
return compatibleMethods[0].Method;
133135
}
134136

135-
return weaklyCompatibleMethods[0].Method;
137+
MethodWithMetadata bestFitMethod = compatibleMethods
138+
.OrderByDescending(m => m.CompatibilityScore)
139+
.First()
140+
;
141+
142+
return bestFitMethod.Method;
136143
}
137144

138145
return null;
139146
}
140147

141148
private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, Type[] parameterTypes,
142-
bool strictСompliance)
149+
out ushort compatibilityScore)
143150
{
144151
int argValueCount = argValues.Length;
145152
int argTypeCount = argTypes.Length;
146153
int parameterCount = parameterTypes.Length;
154+
compatibilityScore = 0;
147155

148156
if (argValueCount != argTypeCount || argTypeCount != parameterCount)
149157
{
@@ -156,32 +164,50 @@ private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, T
156164
Type argType = argTypes[argIndex];
157165
Type parameterType = parameterTypes[argIndex];
158166

159-
if (argType != parameterType)
167+
if (argType == parameterType)
160168
{
161-
if (!strictСompliance
162-
&& NumericHelpers.IsNumericType(argType) && NumericHelpers.IsNumericType(parameterType))
163-
{
164-
object convertedArgValue;
165-
166-
if (!TypeConverter.TryConvertToType(argValue, parameterType, out convertedArgValue))
167-
{
168-
return false;
169-
}
170-
171-
if (argValue != convertedArgValue)
172-
{
173-
return false;
174-
}
169+
compatibilityScore++;
170+
}
171+
else
172+
{
173+
// TODO: It is necessary to calculate the compatibility score based on length
174+
// of inheritance and interface implementation chains.
175+
object convertedArgValue;
175176

176-
continue;
177+
if (!TypeConverter.TryConvertToType(argValue, parameterType, out convertedArgValue))
178+
{
179+
return false;
177180
}
178181

179-
return false;
182+
continue;
180183
}
181184
}
182185

183186
return true;
184187
}
188+
189+
190+
private sealed class MethodWithMetadata
191+
{
192+
public MethodBase Method
193+
{
194+
get;
195+
set;
196+
}
197+
198+
public Type[] ParameterTypes
199+
{
200+
get;
201+
set;
202+
}
203+
204+
/// TODO: In future will need to change type to <code>double</code>
205+
public ushort CompatibilityScore
206+
{
207+
get;
208+
set;
209+
}
210+
}
185211
}
186212
}
187213
#endif

test/MsieJavaScriptEngine.Test.Common.Net4/MsieJavaScriptEngine.Test.Common.Net40.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@
6161
<Compile Include="..\MsieJavaScriptEngine.Test.Common\InteropTestsBase.cs">
6262
<Link>InteropTestsBase.cs</Link>
6363
</Compile>
64+
<Compile Include="..\MsieJavaScriptEngine.Test.Common\Interop\Animals\AnimalTrainer.cs">
65+
<Link>Animals\AnimalTrainer.cs</Link>
66+
</Compile>
67+
<Compile Include="..\MsieJavaScriptEngine.Test.Common\Interop\Animals\Cat.cs">
68+
<Link>Animals\Cat.cs</Link>
69+
</Compile>
70+
<Compile Include="..\MsieJavaScriptEngine.Test.Common\Interop\Animals\Dog.cs">
71+
<Link>Animals\Dog.cs</Link>
72+
</Compile>
73+
<Compile Include="..\MsieJavaScriptEngine.Test.Common\Interop\Animals\IAnimal.cs">
74+
<Link>Animals\IAnimal.cs</Link>
75+
</Compile>
6476
<Compile Include="..\MsieJavaScriptEngine.Test.Common\Interop\Base64Encoder.cs">
6577
<Link>Interop\Base64Encoder.cs</Link>
6678
</Compile>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace MsieJavaScriptEngine.Test.Common.Interop.Animals
2+
{
3+
public sealed class AnimalTrainer
4+
{
5+
public string ExecuteVoiceCommand(IAnimal animal)
6+
{
7+
return animal.Cry();
8+
}
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace MsieJavaScriptEngine.Test.Common.Interop.Animals
2+
{
3+
public sealed class Cat : IAnimal
4+
{
5+
public string Cry()
6+
{
7+
return "Meow!";
8+
}
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace MsieJavaScriptEngine.Test.Common.Interop.Animals
2+
{
3+
public sealed class Dog : IAnimal
4+
{
5+
public string Cry()
6+
{
7+
return "Woof!";
8+
}
9+
}
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace MsieJavaScriptEngine.Test.Common.Interop.Animals
2+
{
3+
public interface IAnimal
4+
{
5+
string Cry();
6+
}
7+
}

test/MsieJavaScriptEngine.Test.Common/Interop/Date.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public static Date Today
1616
get
1717
{
1818
DateTime currentDateTime = DateTime.Today;
19-
Date currentDate = new Date(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day);
19+
var currentDate = new Date(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day);
2020

2121
return currentDate;
2222
}
@@ -43,5 +43,13 @@ public int GetDayOfYear()
4343
(Month > 2 && IsLeapYear(Year) ? 1 : 0)
4444
;
4545
}
46+
47+
public Date AddDays(double value)
48+
{
49+
var dateTime = new DateTime(Year, Month, Day);
50+
DateTime newDateTime = dateTime.AddDays(value);
51+
52+
return new Date(newDateTime.Year, newDateTime.Month, newDateTime.Day);
53+
}
4654
}
4755
}

test/MsieJavaScriptEngine.Test.Common/InteropTestsBase.cs

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using NUnit.Framework;
1010

1111
using MsieJavaScriptEngine.Test.Common.Interop;
12+
using MsieJavaScriptEngine.Test.Common.Interop.Animals;
1213
#if NETCOREAPP1_0
1314
using MsieJavaScriptEngine.Test.Common.Interop.Drawing;
1415
#endif
@@ -305,25 +306,32 @@ public virtual void EmbeddingOfInstanceOfBuiltinReferenceTypeWithMethodIsCorrect
305306
}
306307

307308
[Test]
308-
public virtual void EmbeddingOfInstanceOfCustomValueTypeWithMethodIsCorrect()
309+
public virtual void EmbeddingOfInstanceOfCustomValueTypeWithMethodsIsCorrect()
309310
{
310311
// Arrange
311312
var programmerDayDate = new Date(2015, 9, 13);
312313

313-
const string input = "programmerDay.GetDayOfYear()";
314-
const int targetOutput = 256;
314+
const string input1 = "programmerDay.GetDayOfYear()";
315+
const int targetOutput1 = 256;
316+
317+
const string input2 = @"var smileDay = programmerDay.AddDays(6);
318+
smileDay.GetDayOfYear();";
319+
const int targetOutput2 = 262;
315320

316321
// Act
317-
int output;
322+
int output1;
323+
int output2;
318324

319325
using (var jsEngine = CreateJsEngine())
320326
{
321327
jsEngine.EmbedHostObject("programmerDay", programmerDayDate);
322-
output = jsEngine.Evaluate<int>(input);
328+
output1 = jsEngine.Evaluate<int>(input1);
329+
output2 = jsEngine.Evaluate<int>(input2);
323330
}
324331

325332
// Assert
326-
Assert.AreEqual(targetOutput, output);
333+
Assert.AreEqual(targetOutput1, output1);
334+
Assert.AreEqual(targetOutput2, output2);
327335
}
328336

329337
[Test]
@@ -349,6 +357,38 @@ public virtual void EmbeddingOfInstanceOfCustomReferenceTypeWithMethodIsCorrect(
349357
Assert.AreEqual(targetOutput, output);
350358
}
351359

360+
[Test]
361+
public virtual void CallingOfMethodOfCustomReferenceTypeWithInterfaceParameterIsCorrect()
362+
{
363+
// Arrange
364+
var animalTrainer = new AnimalTrainer();
365+
var cat = new Cat();
366+
var dog = new Dog();
367+
368+
const string input1 = "animalTrainer.ExecuteVoiceCommand(cat)";
369+
const string targetOutput1 = "Meow!";
370+
371+
const string input2 = "animalTrainer.ExecuteVoiceCommand(dog)";
372+
const string targetOutput2 = "Woof!";
373+
374+
// Act
375+
string output1;
376+
string output2;
377+
378+
using (var jsEngine = CreateJsEngine())
379+
{
380+
jsEngine.EmbedHostObject("animalTrainer", animalTrainer);
381+
jsEngine.EmbedHostObject("cat", cat);
382+
jsEngine.EmbedHostObject("dog", dog);
383+
output1 = jsEngine.Evaluate<string>(input1);
384+
output2 = jsEngine.Evaluate<string>(input2);
385+
}
386+
387+
// Assert
388+
Assert.AreEqual(targetOutput1, output1);
389+
Assert.AreEqual(targetOutput2, output2);
390+
}
391+
352392
#endregion
353393

354394
#region Delegates
@@ -903,25 +943,31 @@ public virtual void EmbeddingOfBuiltinValueTypeWithMethodIsCorrect()
903943
}
904944

905945
[Test]
906-
public virtual void EmbeddingOfBuiltinReferenceTypeWithMethodIsCorrect()
946+
public virtual void EmbeddingOfBuiltinReferenceTypeWithMethodsIsCorrect()
907947
{
908948
// Arrange
909949
Type mathType = typeof(Math);
910950

911-
const string input = "Math2.Max(5.37, 5.56)";
912-
const double targetOutput = 5.56;
951+
const string input1 = "Math2.Max(5.37, 5.56)";
952+
const double targetOutput1 = 5.56;
953+
954+
const string input2 = "Math2.Log10(23)";
955+
const double targetOutput2 = 1.36172783601759;
913956

914957
// Act
915-
double output;
958+
double output1;
959+
double output2;
916960

917961
using (var jsEngine = CreateJsEngine())
918962
{
919963
jsEngine.EmbedHostType("Math2", mathType);
920-
output = jsEngine.Evaluate<double>(input);
964+
output1 = jsEngine.Evaluate<double>(input1);
965+
output2 = Math.Round(jsEngine.Evaluate<double>(input2), 14);
921966
}
922967

923968
// Assert
924-
Assert.AreEqual(targetOutput, output);
969+
Assert.AreEqual(targetOutput1, output1);
970+
Assert.AreEqual(targetOutput2, output2);
925971
}
926972

927973
[Test]

0 commit comments

Comments
 (0)