diff --git a/Jint.Tests/Runtime/InteropInterfaceExtendTests.cs b/Jint.Tests/Runtime/InteropInterfaceExtendTests.cs new file mode 100644 index 0000000000..fc50064581 --- /dev/null +++ b/Jint.Tests/Runtime/InteropInterfaceExtendTests.cs @@ -0,0 +1,151 @@ +using Jint.Runtime; + +namespace Jint.Tests.Runtime; + +public class InterfaceTests +{ + public interface I0 + { + string NameI0 { get; } + string OverloadSuperMethod(); + string SubPropertySuperMethod(); + } + + public interface I1 : I0 + { + string Name { get; } + string OverloadSuperMethod(int x); + new string SubPropertySuperMethod { get; } + } + + public class Super + { + public string Name { get; } = "Super"; + } + + public class CI1 : Super, I1 + { + public new string Name { get; } = "CI1"; + + public string NameI0 { get; } = "I0.Name"; + + string I1.Name { get; } = "CI1 as I1"; + + string I1.SubPropertySuperMethod { get; } = "I1.SubPropertySuperMethod"; + + public string OverloadSuperMethod() + { + return "I0.OverloadSuperMethod()"; + } + + public string OverloadSuperMethod(int x) + { + return $"I1.OverloadSuperMethod(int {x})"; + } + + public string SubPropertySuperMethod() + { + return "I0.SubPropertySuperMethod()"; + } + } + + public class Indexer + { + private readonly T t; + + public Indexer(T t) + { + this.t = t; + } + + public T this[int index] + { + get { return t; } + } + } + + public class InterfaceHolder + { + public InterfaceHolder() + { + var ci1 = new CI1(); + this.ci1 = ci1; + this.i1 = ci1; + this.super = ci1; + + this.IndexerCI1 = new Indexer(ci1); + this.IndexerI1 = new Indexer(ci1); + this.IndexerSuper = new Indexer(ci1); + } + + public readonly CI1 ci1; + public readonly I1 i1; + public readonly Super super; + + public CI1 CI1 { get => ci1; } + public I1 I1 { get => i1; } + public Super Super { get => super; } + + public CI1 GetCI1() => ci1; + public I1 GetI1() => i1; + public Super GetSuper() => super; + + public Indexer IndexerCI1 { get; } + public Indexer IndexerI1 { get; } + public Indexer IndexerSuper { get; } + } + + private readonly Engine _engine; + private readonly InterfaceHolder holder; + + public InterfaceTests() + { + holder = new InterfaceHolder(); + _engine = new Engine(cfg => cfg.AllowClr( + typeof(CI1).Assembly, + typeof(Console).Assembly, + typeof(File).Assembly)) + .SetValue("log", new Action(Console.WriteLine)) + .SetValue("assert", new Action(Assert.True)) + .SetValue("equal", new Action(Assert.Equal)) + .SetValue("holder", holder) + ; + } + + [Fact] + public void CallSuperPropertyFromInterface() + { + Assert.Equal(holder.I1.NameI0, _engine.Evaluate("holder.I1.NameI0")); + } + + [Fact] + public void CallOverloadSuperMethod() + { + Assert.Equal( + holder.I1.OverloadSuperMethod(1), + _engine.Evaluate("holder.I1.OverloadSuperMethod(1)")); + Assert.Equal( + holder.I1.OverloadSuperMethod(), + _engine.Evaluate("holder.I1.OverloadSuperMethod()")); + } + + [Fact] + public void CallSubPropertySuperMethod_SubProperty() + { + Assert.Equal( + holder.I1.SubPropertySuperMethod, + _engine.Evaluate("holder.I1.SubPropertySuperMethod")); + } + + [Fact] + public void CallSubPropertySuperMethod_SuperMethod() + { + var ex = Assert.Throws(() => + { + Assert.Equal( + holder.I1.SubPropertySuperMethod(), + _engine.Evaluate("holder.I1.SubPropertySuperMethod()")); + }); + Assert.Equal("Property 'SubPropertySuperMethod' of object is not a function", ex.Message); + } +} diff --git a/Jint/Runtime/Interop/TypeResolver.cs b/Jint/Runtime/Interop/TypeResolver.cs index 45c0e45d29..94de267184 100644 --- a/Jint/Runtime/Interop/TypeResolver.cs +++ b/Jint/Runtime/Interop/TypeResolver.cs @@ -283,21 +283,26 @@ void AddMethod(MethodInfo m) } } } + foreach (var m in type.GetMethods(bindingFlags)) { AddMethod(m); } + foreach (var iface in type.GetInterfaces()) + { + foreach (var m in iface.GetMethods()) + { + AddMethod(m); + } + } + // TPC: need to grab the extension methods here - for overloads if (engine._extensionMethods.TryGetExtensionMethods(type, out var extensionMethods)) { foreach (var methodInfo in extensionMethods) { - if (memberNameComparer.Equals(methodInfo.Name, memberName)) - { - methods ??= new List(); - methods.Add(methodInfo); - } + AddMethod(methodInfo); } }