From 999ae15266098f91226f47e536ee6dbdc86e3864 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Wed, 3 Aug 2016 18:28:23 +0200 Subject: [PATCH] Use a custom contract resolver in the CommandResposeFactory, to ensure that properties with private setters have their values set, too. --- .../ChromeDevTools/CommandResponseFactory.cs | 18 +++- .../Serialization/MessageContractResolver.cs | 25 ++++- .../CommandResponseFactoryTests.cs | 32 +++++++ .../MasterDevs.ChromeDevTools.Tests.csproj | 94 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++++ .../response-1.json | 61 ++++++++++++ source/MasterDevs.ChromeDevTools.sln | 8 +- 7 files changed, 269 insertions(+), 5 deletions(-) create mode 100644 source/MasterDevs.ChromeDevTools.Tests/CommandResponseFactoryTests.cs create mode 100644 source/MasterDevs.ChromeDevTools.Tests/MasterDevs.ChromeDevTools.Tests.csproj create mode 100644 source/MasterDevs.ChromeDevTools.Tests/Properties/AssemblyInfo.cs create mode 100644 source/MasterDevs.ChromeDevTools.Tests/response-1.json diff --git a/source/ChromeDevTools/CommandResponseFactory.cs b/source/ChromeDevTools/CommandResponseFactory.cs index 562dacaa..6e220e53 100644 --- a/source/ChromeDevTools/CommandResponseFactory.cs +++ b/source/ChromeDevTools/CommandResponseFactory.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json.Linq; +using MasterDevs.ChromeDevTools.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; using System; namespace MasterDevs.ChromeDevTools @@ -8,10 +11,21 @@ public class CommandResponseFactory : ICommandResponseFactory private readonly IMethodTypeMap _methodTypeMap; private readonly ICommandFactory _commandFactory; + /// + /// Used to deserialize command responses from JSON to .NET objects. + /// + private readonly JsonSerializer _serializer; + public CommandResponseFactory(IMethodTypeMap methodTypeMap, ICommandFactory commandFactory) + : this(methodTypeMap, commandFactory, new JsonSerializer() { ContractResolver = new MessageContractResolver() }) + { + } + + public CommandResponseFactory(IMethodTypeMap methodTypeMap, ICommandFactory commandFactory, JsonSerializer serializer) { _methodTypeMap = methodTypeMap; _commandFactory = commandFactory; + _serializer = serializer; } public ICommandResponse Create(byte[] responseBytes) @@ -38,7 +52,7 @@ public ICommandResponse Create(string responseText) } var genericEventType = typeof(CommandResponse<>); var commandResponseType = genericEventType.MakeGenericType(typeInferredFromMethod); - var result = jObject.ToObject(commandResponseType); + var result = jObject.ToObject(commandResponseType, _serializer); return result as ICommandResponse; } diff --git a/source/ChromeDevTools/Serialization/MessageContractResolver.cs b/source/ChromeDevTools/Serialization/MessageContractResolver.cs index 24ebd83a..d335c711 100644 --- a/source/ChromeDevTools/Serialization/MessageContractResolver.cs +++ b/source/ChromeDevTools/Serialization/MessageContractResolver.cs @@ -1,9 +1,11 @@ -using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using System; +using System.Reflection; namespace MasterDevs.ChromeDevTools.Serialization { - internal class MessageContractResolver : DefaultContractResolver + public class MessageContractResolver : DefaultContractResolver { protected override string ResolvePropertyName(string propertyName) { @@ -17,5 +19,24 @@ protected override string ResolvePropertyName(string propertyName) } return Char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1); } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var prop = base.CreateProperty(member, memberSerialization); + + // Add support for properties with private setters; for example, Response.Result has a private setter and its + // value is not assigned by default. + if (!prop.Writable) + { + var property = member as PropertyInfo; + if (property != null) + { + var hasPrivateSetter = property.GetSetMethod(true) != null; + prop.Writable = hasPrivateSetter; + } + } + + return prop; + } } } \ No newline at end of file diff --git a/source/MasterDevs.ChromeDevTools.Tests/CommandResponseFactoryTests.cs b/source/MasterDevs.ChromeDevTools.Tests/CommandResponseFactoryTests.cs new file mode 100644 index 00000000..f4a5bb0d --- /dev/null +++ b/source/MasterDevs.ChromeDevTools.Tests/CommandResponseFactoryTests.cs @@ -0,0 +1,32 @@ +using System; +using MasterDevs.ChromeDevTools.Protocol.iOS.DOM; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; + +namespace MasterDevs.ChromeDevTools.Tests +{ + [TestClass] + public class CommandResponseFactoryTests + { + [TestMethod] + [DeploymentItem("response-1.json")] + public void CreateTest() + { + string json = File.ReadAllText("response-1.json"); + + MethodTypeMap map = new MethodTypeMap("iOS"); + CommandFactory commandFactory = new CommandFactory(); + CommandResponseFactory responseFactory = new CommandResponseFactory(map, commandFactory); + + var command = commandFactory.Create(); + var response = responseFactory.Create(json); + + Assert.IsInstanceOfType(response, typeof(CommandResponse)); + + var responseTyped = (CommandResponse)response; + + Assert.AreEqual(1, responseTyped.Id); + Assert.IsNotNull(responseTyped.Result); + } + } +} diff --git a/source/MasterDevs.ChromeDevTools.Tests/MasterDevs.ChromeDevTools.Tests.csproj b/source/MasterDevs.ChromeDevTools.Tests/MasterDevs.ChromeDevTools.Tests.csproj new file mode 100644 index 00000000..87d4cc0e --- /dev/null +++ b/source/MasterDevs.ChromeDevTools.Tests/MasterDevs.ChromeDevTools.Tests.csproj @@ -0,0 +1,94 @@ + + + + Debug + AnyCPU + {4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72} + Library + Properties + MasterDevs.ChromeDevTools.Tests + MasterDevs.ChromeDevTools.Tests + v4.6.1 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {c2508ee5-aab2-4275-88c9-7da9d1961336} + MasterDevs.ChromeDevTools + + + + + PreserveNewest + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/source/MasterDevs.ChromeDevTools.Tests/Properties/AssemblyInfo.cs b/source/MasterDevs.ChromeDevTools.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b4d51a0a --- /dev/null +++ b/source/MasterDevs.ChromeDevTools.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MasterDevs.ChromeDevTools.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MasterDevs.ChromeDevTools.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4cfeba12-2ecb-4c17-9ea1-ad79c39eea72")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/MasterDevs.ChromeDevTools.Tests/response-1.json b/source/MasterDevs.ChromeDevTools.Tests/response-1.json new file mode 100644 index 00000000..3305d417 --- /dev/null +++ b/source/MasterDevs.ChromeDevTools.Tests/response-1.json @@ -0,0 +1,61 @@ +{ + "result": { + "root": { + "nodeId": 16, + "nodeType": 9, + "nodeName": "#document", + "localName": "", + "nodeValue": "", + "childNodeCount": 2, + "children": [ + { + "nodeId": 17, + "nodeType": 10, + "nodeName": "html", + "localName": "", + "nodeValue": "", + "publicId": "", + "systemId": "", + "internalSubset": "" + }, + { + "nodeId": 18, + "nodeType": 1, + "nodeName": "HTML", + "localName": "html", + "nodeValue": "", + "childNodeCount": 2, + "children": [ + { + "nodeId": 19, + "nodeType": 1, + "nodeName": "HEAD", + "localName": "head", + "nodeValue": "", + "childNodeCount": 4, + "attributes": [] + }, + { + "nodeId": 20, + "nodeType": 1, + "nodeName": "BODY", + "localName": "body", + "nodeValue": "", + "childNodeCount": 2, + "attributes": [ "class", "transitions-on ios" ], + "role": "group" + } + ], + "attributes": [ "manifest", "manifest.appcache" ], + "role": "" + } + ], + "frameId": "0.1", + "documentURL": "https://mycompany/25/ios/v3.2.14/", + "baseURL": "https://mycompany/25/ios/v3.2.14/", + "xmlVersion": "", + "role": "" + } + }, + "id": 1 +} \ No newline at end of file diff --git a/source/MasterDevs.ChromeDevTools.sln b/source/MasterDevs.ChromeDevTools.sln index a20ee809..c56b4d4f 100644 --- a/source/MasterDevs.ChromeDevTools.sln +++ b/source/MasterDevs.ChromeDevTools.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{0D43D20B-6D51-4CBC-BD30-F17B8CA65678}" ProjectSection(SolutionItems) = preProject @@ -24,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.ProtocolGenerator.Tests", "ProtocolGenerator.Tests\MasterDevs.ChromeDevTools.ProtocolGenerator.Tests.csproj", "{4C3A1910-79C5-43C0-8599-89921482B38B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.Tests", "MasterDevs.ChromeDevTools.Tests\MasterDevs.ChromeDevTools.Tests.csproj", "{4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,6 +48,10 @@ Global {4C3A1910-79C5-43C0-8599-89921482B38B}.Debug|Any CPU.Build.0 = Debug|Any CPU {4C3A1910-79C5-43C0-8599-89921482B38B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C3A1910-79C5-43C0-8599-89921482B38B}.Release|Any CPU.Build.0 = Release|Any CPU + {4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CFEBA12-2ECB-4C17-9EA1-AD79C39EEA72}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE