using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; using WireMock.Util; namespace WireMock.Matchers; /// /// Generic AbstractJsonPartialMatcher /// public abstract class AbstractJsonPartialMatcher : JsonMatcher { /// /// Support Regex /// public bool Regex { get; } /// /// Initializes a new instance of the class. /// /// The string value to check for equality. /// Ignore the case from the PropertyName and PropertyValue (string only). /// Support Regex. protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool regex = false) : base(value, ignoreCase) { Regex = regex; } /// /// Initializes a new instance of the class. /// /// The object value to check for equality. /// Ignore the case from the PropertyName and PropertyValue (string only). /// Support Regex. protected AbstractJsonPartialMatcher(object value, bool ignoreCase = false, bool regex = false) : base(value, ignoreCase) { Regex = regex; } /// /// Initializes a new instance of the class. /// /// The match behaviour. /// The value to check for equality. /// Ignore the case from the PropertyName and PropertyValue (string only). /// Support Regex. protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false) : base(matchBehaviour, value, ignoreCase) { Regex = regex; } /// protected override bool IsMatch(JToken? value, JToken? input) { if (value == null || value == input) { return true; } if (Regex && value.Type == JTokenType.String && input != null) { var valueAsString = value.ToString(); var (valid, result) = RegexUtils.MatchRegex(valueAsString, input.ToString()); if (valid) { return result; } } if (input != null && ((value.Type == JTokenType.Guid && input.Type == JTokenType.String) || (value.Type == JTokenType.String && input.Type == JTokenType.Guid))) { return IsMatch(value.ToString(), input.ToString()); } if (input == null || value.Type != input.Type) { return false; } switch (value.Type) { case JTokenType.Object: var nestedValues = value.ToObject>(); return nestedValues?.Any() != true || nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key))); case JTokenType.Array: var valuesArray = value.ToObject(); var tokenArray = input.ToObject(); if (valuesArray?.Any() != true) { return true; } return tokenArray?.Any() == true && valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken))); default: return IsMatch(value.ToString(), input.ToString()); } } /// /// Check if two strings are a match (matching can be done exact or wildcard) /// protected abstract bool IsMatch(string value, string input); }