| File: FilterHelper.cs | Web Access |
| Project: src\vstest\src\Microsoft.TestPlatform.Filter.Source\Microsoft.TestPlatform.Filter.Source.csproj (Microsoft.TestPlatform.Filter.Source) |
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #nullable enable using System; using System.Collections.Generic; using System.Globalization; using System.Text; #if !IS_VSTEST_REPO using Microsoft.CodeAnalysis; #endif #if IS_VSTEST_REPO using static Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.Resources; #endif // Because FilterHelper is public, changing the namespace for filter package to avoid collisions. // This also makes it such that all types in filter source package use the same Common.Filtering namespace. #if IS_VSTEST_REPO namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; #else namespace Microsoft.VisualStudio.TestPlatform.Common.Filtering; #endif #if IS_VSTEST_REPO public static class FilterHelper #else [Embedded] internal static class FilterHelper #endif { public const char EscapeCharacter = '\\'; private static readonly char[] SpecialCharacters = ['\\', '(', ')', '&', '|', '=', '!', '~']; private static readonly HashSet<char> SpecialCharactersSet = new(SpecialCharacters); #if !IS_VSTEST_REPO private const string TestCaseFilterEscapeException = "Filter string '{0}' includes unrecognized escape sequence."; #endif /// <summary> /// Escapes a set of special characters for filter (%, (, ), &, |, =, !, ~) by replacing them with their escape sequences. /// </summary> /// <param name="str">The input string that contains the text to convert.</param> /// <returns>A string of characters with special characters converted to their escaped form.</returns> public static string Escape(string str) { #if IS_VSTEST_REPO ValidateArg.NotNull(str, nameof(str)); #endif if (str.IndexOfAny(SpecialCharacters) < 0) { return str; } var builder = new StringBuilder(); for (int i = 0; i < str.Length; ++i) { var currentChar = str[i]; if (SpecialCharactersSet.Contains(currentChar)) { builder.Append(EscapeCharacter); } builder.Append(currentChar); } return builder.ToString(); } /// <summary> /// Converts any escaped characters in the input filter string. /// </summary> /// <param name="str">The input string that contains the text to convert.</param> /// <returns>A filter string of characters with any escaped characters converted to their un-escaped form.</returns> public static string Unescape(string str) { #if IS_VSTEST_REPO ValidateArg.NotNull(str, nameof(str)); #endif if (str.IndexOf(EscapeCharacter) < 0) { return str; } var builder = new StringBuilder(); for (int i = 0; i < str.Length; ++i) { var currentChar = str[i]; if (currentChar == EscapeCharacter) { if (++i == str.Length || !SpecialCharactersSet.Contains(currentChar = str[i])) { // "\" should be followed by a special character. throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, TestCaseFilterEscapeException, str)); } } // Strictly speaking, string to be un-escaped shouldn't contain any of the special characters, // other than being part of escape sequence, but we will ignore that to avoid additional overhead. builder.Append(currentChar); } return builder.ToString(); } }