diff --git a/.gitignore b/.gitignore index 72ab9c5..e327939 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,9 @@ /Win32 /Win64 +Build/TestAndBuild.fb7lck +*.fbl7 +*.fbpInf +*.rc +*.drc +*.map diff --git a/Build/TestAndBuild.fbp7 b/Build/TestAndBuild.fbp7 new file mode 100644 index 0000000..f8345fa Binary files /dev/null and b/Build/TestAndBuild.fbp7 differ diff --git a/Delphi.Mocks.InterfaceProxy.pas b/Delphi.Mocks.InterfaceProxy.pas index bbd2284..2972aac 100644 --- a/Delphi.Mocks.InterfaceProxy.pas +++ b/Delphi.Mocks.InterfaceProxy.pas @@ -30,15 +30,15 @@ interface uses Rtti, SysUtils, + Generics.Collections, Delphi.Mocks, Delphi.Mocks.Interfaces, - // Delphi.Mocks.VirtualInterface, Delphi.Mocks.ProxyBase; type TProxyBaseInvokeEvent = procedure (Method: TRttiMethod; const Args: TArray; out Result: TValue) of object; - TSetupMode = (None,Behavior,Expectation); + TSetupMode = (None, Behavior, Expectation); TInterfaceProxy = class(TBaseProxy) private type @@ -51,11 +51,12 @@ TProxyVirtualInterface = class(TVirtualInterface) constructor Create(AProxy : TInterfaceProxy; AInterface: Pointer; InvokeEvent: TVirtualInterfaceInvokeEvent); end; private - FVirtualInterface : IInterface; + FVirtualInterfaces : TDictionary; protected function InternalQueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; function QueryInterface(const IID: TGUID; out Obj): HRESULT; override; function Proxy : T;override; + function CastAs : I; public constructor Create;override; destructor Destroy;override; @@ -69,22 +70,40 @@ implementation { TInterfaceProxy } +function TInterfaceProxy.CastAs: I; +var + virtualProxy : TProxyVirtualInterface; +begin + virtualProxy := TProxyVirtualInterface.Create(Self, TypeInfo(I), Self.DoInvoke); + + FVirtualInterfaces.Add(GetTypeData(TypeInfo(I)).Guid, virtualProxy); +end; + constructor TInterfaceProxy.Create; +var + virtualProxy : TProxyVirtualInterface; begin inherited; - FVirtualInterface := TProxyVirtualInterface.Create(Self,TypeInfo(T),Self.DoInvoke); + + FVirtualInterfaces := TDictionary.Create; + + virtualProxy := TProxyVirtualInterface.Create(Self, TypeInfo(T), Self.DoInvoke); + + FVirtualInterfaces.Add(GetTypeData(TypeInfo(T)).Guid, virtualProxy); end; destructor TInterfaceProxy.Destroy; begin - FVirtualInterface := nil; + FVirtualInterfaces.Clear; + FreeAndNil(FVirtualInterfaces); + inherited; end; function TInterfaceProxy.InternalQueryInterface(const IID: TGUID; out Obj): HRESULT; begin Result := E_NOINTERFACE; - if (IsEqualGUID(IID,IInterface)) then + if (IsEqualGUID(IID, IInterface)) then if GetInterface(IID, Obj) then Result := 0; end; @@ -92,30 +111,44 @@ function TInterfaceProxy.InternalQueryInterface(const IID: TGUID; out Obj): H function TInterfaceProxy.Proxy: T; var pInfo : PTypeInfo; + virtualProxy : IInterface; begin pInfo := TypeInfo(T); - if FVirtualInterface.QueryInterface(GetTypeData(pInfo).Guid,result) <> 0 then + + if FVirtualInterfaces.ContainsKey(GetTypeData(pInfo).Guid) then + virtualProxy := FVirtualInterfaces.Items[GetTypeData(pInfo).Guid] + else + raise EMockNoProxyException.Create('Error proxy casting to interface'); + + if virtualProxy.QueryInterface(GetTypeData(pInfo).Guid,result) <> 0 then raise EMockNoProxyException.Create('Error casting to interface ' + string(pInfo.Name) + ' , proxy does not appear to implememnt T'); end; function TInterfaceProxy.QueryInterface(const IID: TGUID; out Obj): HRESULT; +var + virtualProxy : IInterface; begin Result := E_NOINTERFACE; - if (FVirtualInterface <> nil) then - Result := FVirtualInterface.QueryInterface(IID, Obj); + + if (FVirtualInterfaces <> nil) then + if (FVirtualInterfaces.Count <> 0) then + if (FVirtualInterfaces.ContainsKey(IID)) then + begin + virtualProxy := FVirtualInterfaces.Items[IID]; + Result := virtualProxy.QueryInterface(IID, Obj); + end; + if result <> 0 then Result := inherited; - end; { TInterfaceProxy.TProxyVirtualInterface } -constructor TInterfaceProxy.TProxyVirtualInterface.Create( - AProxy: TInterfaceProxy; AInterface: Pointer; - InvokeEvent: TVirtualInterfaceInvokeEvent); +constructor TInterfaceProxy.TProxyVirtualInterface.Create(AProxy: TInterfaceProxy; + AInterface: Pointer; InvokeEvent: TVirtualInterfaceInvokeEvent); begin FProxy := AProxy; - inherited Create(Ainterface,InvokeEvent); + inherited Create(Ainterface, InvokeEvent); end; diff --git a/Sample1.RES b/Sample1.RES index adc2449..c0e155d 100644 Binary files a/Sample1.RES and b/Sample1.RES differ diff --git a/Tests/Delphi.Mocks.Tests.InterfaceProxy.pas b/Tests/Delphi.Mocks.Tests.InterfaceProxy.pas new file mode 100644 index 0000000..c532ed7 --- /dev/null +++ b/Tests/Delphi.Mocks.Tests.InterfaceProxy.pas @@ -0,0 +1,91 @@ +{***************************************************************************} +{ } +{ Delphi.Mocks } +{ } +{ Copyright (C) 2011 Vincent Parrett } +{ } +{ http://www.finalbuilder.com } +{ } +{ } +{***************************************************************************} +{ } +{ Licensed under the Apache License, Version 2.0 (the "License"); } +{ you may not use this file except in compliance with the License. } +{ You may obtain a copy of the License at } +{ } +{ http://www.apache.org/licenses/LICENSE-2.0 } +{ } +{ Unless required by applicable law or agreed to in writing, software } +{ distributed under the License is distributed on an "AS IS" BASIS, } +{ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. } +{ See the License for the specific language governing permissions and } +{ limitations under the License. } +{ } +{***************************************************************************} + +unit Delphi.Mocks.Tests.InterfaceProxy; + +interface + +uses + TestFramework; + +type + {$M+} + ISimpleInterface = Interface + ['{F1731F12-2453-4818-A785-997AF7A3D51F}'] + End; + + ISecondSimpleInterface = Interface + ['{C7191239-2E89-4D3A-9D1B-F894BACBBB39}'] + End; + {$M-} + + TTestInterfaceProxy = class(TTestCase) + published + procedure Does_A_Proxy_Implement_Two_Interfaces_After_A_Cast; + procedure After_Destruction_Are_All_The_Interfaces_Cleaned_Up; + end; + +//TODO: IProxy will not allow a function of CastAs on it, class does however. + +implementation + +uses + SysUtils, + Delphi.Mocks, + Delphi.Mocks.InterfaceProxy; + +{ TTestInterfaceProxy } + +procedure TTestInterfaceProxy.After_Destruction_Are_All_The_Interfaces_Cleaned_Up; +var + simpleInterface: TInterfaceProxy; + secondInterface: ISecondSimpleInterface; +begin + simpleInterface := TInterfaceProxy.Create; + secondInterface := simpleInterface.CastAs; + + CheckNotNull(secondInterface, 'The second interface is not implemented!'); +end; + +procedure TTestInterfaceProxy.Does_A_Proxy_Implement_Two_Interfaces_After_A_Cast; +var + simpleInterface: TInterfaceProxy; + secondInterface : ISecondSimpleInterface; +begin + simpleInterface := TInterfaceProxy.Create; + try + simpleInterface.CastAs; + + simpleInterface.QueryInterface(ISecondSimpleInterface, secondInterface); + + CheckNotNull(secondInterface, 'The second interface is not implemented!'); + finally + FreeAndNil(simpleInterface); + end; +end; + +initialization + TestFramework.RegisterTest(TTestInterfaceProxy.Suite); +end. diff --git a/Tests/Delphi.Mocks.Tests.OpenArrayIntf.pas b/Tests/Delphi.Mocks.Tests.OpenArrayIntf.pas index 2c4cc7b..69a20e9 100644 --- a/Tests/Delphi.Mocks.Tests.OpenArrayIntf.pas +++ b/Tests/Delphi.Mocks.Tests.OpenArrayIntf.pas @@ -44,7 +44,7 @@ procedure TestIOpenArray.TestMyMethodDynamicArray; Intf := Mock; - // privileged instruction :-( + //TODO: Fix the privileged instruction. Something to do with TValue not liking Dynamic Arrays CheckEquals(3, Intf.MyMethod([Obj], 1)); end; diff --git a/Tests/Delphi.Mocks.Tests.dpr b/Tests/Delphi.Mocks.Tests.dpr index db01c5b..aaedf36 100644 --- a/Tests/Delphi.Mocks.Tests.dpr +++ b/Tests/Delphi.Mocks.Tests.dpr @@ -46,7 +46,8 @@ uses Delphi.Mocks.Tests.Base in 'Delphi.Mocks.Tests.Base.pas', Delphi.Mocks.Tests.ObjectProxy in 'Delphi.Mocks.Tests.ObjectProxy.pas', Delphi.Mocks.Examples.Objects in 'Delphi.Mocks.Examples.Objects.pas', - Delphi.Mocks.ReturnTypePatch in '..\Delphi.Mocks.ReturnTypePatch.pas'; + Delphi.Mocks.ReturnTypePatch in '..\Delphi.Mocks.ReturnTypePatch.pas', + Delphi.Mocks.Tests.InterfaceProxy in 'Delphi.Mocks.Tests.InterfaceProxy.pas'; {$R *.RES} diff --git a/Tests/Delphi.Mocks.Tests.dproj b/Tests/Delphi.Mocks.Tests.dproj index 1cc9354..c436221 100644 --- a/Tests/Delphi.Mocks.Tests.dproj +++ b/Tests/Delphi.Mocks.Tests.dproj @@ -112,6 +112,13 @@ + + + + + + + Cfg_2 Base @@ -178,19 +185,3 @@ - - diff --git a/Tests/Delphi.Mocks.Tests.res b/Tests/Delphi.Mocks.Tests.res index 15f1ffe..5dd56e5 100644 Binary files a/Tests/Delphi.Mocks.Tests.res and b/Tests/Delphi.Mocks.Tests.res differ