| File: Serialization\DiscoveryCriteriaConverter.cs | Web Access |
| Project: src\vstest\src\Microsoft.TestPlatform.CommunicationUtilities\Microsoft.TestPlatform.CommunicationUtilities.csproj (Microsoft.TestPlatform.CommunicationUtilities) |
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #if NETCOREAPP using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; /// <summary> /// JSON converter for <see cref="DiscoveryCriteria"/> that skips the computed <c>Sources</c> property /// (marked with <c>[IgnoreDataMember]</c>) during serialization and populates <c>AdapterSourceMap</c> /// and other private-setter properties via reflection during deserialization. /// </summary> internal class DiscoveryCriteriaConverter : JsonConverter<DiscoveryCriteria> { /// <inheritdoc/> public override DiscoveryCriteria? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { return null; } using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; var adapterSourceMap = DeserializeProperty<Dictionary<string, IEnumerable<string>>>(root, "AdapterSourceMap", options); var frequency = DeserializeProperty<long>(root, "FrequencyOfDiscoveredTestsEvent", options); var timeout = DeserializeProperty<TimeSpan>(root, "DiscoveredTestEventTimeout", options); var runSettings = root.TryGetProperty("RunSettings", out var rs) && rs.ValueKind != JsonValueKind.Null ? rs.GetString() : null; var package = root.TryGetProperty("Package", out var pkg) && pkg.ValueKind != JsonValueKind.Null ? pkg.GetString() : null; var testCaseFilter = root.TryGetProperty("TestCaseFilter", out var tcf) && tcf.ValueKind != JsonValueKind.Null ? tcf.GetString() : null; var testSessionInfo = DeserializeProperty<TestSessionInfo>(root, "TestSessionInfo", options); var criteria = new DiscoveryCriteria(); // Set private-setter properties via reflection. var type = typeof(DiscoveryCriteria); type.GetProperty(nameof(DiscoveryCriteria.AdapterSourceMap))!.SetValue(criteria, adapterSourceMap); type.GetProperty(nameof(DiscoveryCriteria.FrequencyOfDiscoveredTestsEvent))!.SetValue(criteria, frequency); type.GetProperty(nameof(DiscoveryCriteria.DiscoveredTestEventTimeout))!.SetValue(criteria, timeout); type.GetProperty(nameof(DiscoveryCriteria.RunSettings))!.SetValue(criteria, runSettings); criteria.Package = package; criteria.TestCaseFilter = testCaseFilter; criteria.TestSessionInfo = testSessionInfo; return criteria; } /// <inheritdoc/> public override void Write(Utf8JsonWriter writer, DiscoveryCriteria value, JsonSerializerOptions options) { writer.WriteStartObject(); // Serialize [DataMember] properties in declaration order — skip Sources which has [IgnoreDataMember]. WriteProperty(writer, "Package", value.Package, options); WriteProperty(writer, "AdapterSourceMap", value.AdapterSourceMap, options); writer.WriteNumber("FrequencyOfDiscoveredTestsEvent", value.FrequencyOfDiscoveredTestsEvent); WriteProperty(writer, "DiscoveredTestEventTimeout", value.DiscoveredTestEventTimeout, options); WriteProperty(writer, "RunSettings", value.RunSettings, options); WriteProperty(writer, "TestCaseFilter", value.TestCaseFilter, options); WriteProperty(writer, "TestSessionInfo", value.TestSessionInfo, options); writer.WriteEndObject(); } private static T? DeserializeProperty<T>(JsonElement element, string name, JsonSerializerOptions options) { if (element.TryGetProperty(name, out var prop) && prop.ValueKind != JsonValueKind.Null) { return StjSafe.Deserialize<T>(prop, options); } return default; } private static void WriteProperty<T>(Utf8JsonWriter writer, string name, T value, JsonSerializerOptions options) { writer.WritePropertyName(name); StjSafe.Serialize(writer, value, options); } } #endif