/// <summary> /// Replaces a tokenized input string with replacement values. Wildcard support is optional. /// </summary> /// <param name="tokenizedValue"> The input string containing tokenized values. </param> /// <param name="optionalWildcardTokenReplacement"> An optional wildcard token replacement strategy. </param> /// <returns> A string value with all possible replacements made. </returns> public string ExpandTokens(string tokenizedValue, ITokenReplacement optionalWildcardTokenReplacement) { if (string.IsNullOrWhiteSpace(tokenizedValue)) { return(tokenizedValue); } // clean token collection this.PreviousExpansionTokens.Clear(); tokenizedValue = Regex.Replace(tokenizedValue, TokenizerRegEx, (m) => this.ReplacementMatcherEx(m, optionalWildcardTokenReplacement), RegexOptions.IgnorePatternWhitespace); return(tokenizedValue); }
/// <summary> /// Private method used to match and process tokenized regular expressions. /// </summary> /// <param name="match"> The regular express match object. </param> /// <param name="wildcardTokenReplacement"> The wildcard token replacement strategy to use in the event a predefined token replacement strategy lookup failed. </param> /// <returns> The token-resolved string value. </returns> private string ReplacementMatcherEx(Match match, ITokenReplacement wildcardTokenReplacement) { // ${ .token.token.token_end (`arg0`, ..) } string firstToken, rawToken = null; string[] tokens; string[] argumentList = null; object tokenLogicalValue, tokenReplacementValue = null; ITokenReplacement tokenReplacement; bool keyNotFound, tryWildcard; rawToken = match.Groups[1].Success ? match.Groups[1].Value : null; argumentList = match.Groups[2].Success ? this.GetArgs(match.Groups[2].Value) : null; if (string.IsNullOrWhiteSpace(rawToken)) { return(GetOriginalValueOrThrowException(this.StrictMatching, match.Value, "token missing")); } // break any token paths into token list tokens = rawToken.Split(new char[] { TOKENIZER_LOGICAL_PROPERTY_PATH_CHAR }, StringSplitOptions.RemoveEmptyEntries); if ((object)tokens == null || tokens.Length <= 0) { return(null); } firstToken = tokens[0]; tokens = tokens.Skip(1).ToArray(); // add to token collection this.PreviousExpansionTokens.Add(firstToken); keyNotFound = !this.TokenReplacementStrategies.TryGetValue(firstToken, out tokenReplacement); tryWildcard = keyNotFound && (object)wildcardTokenReplacement != null; if (keyNotFound && !tryWildcard) { return(GetOriginalValueOrThrowException(this.StrictMatching, match.Value, "token unknown")); } try { if (!tryWildcard) { tokenReplacementValue = tokenReplacement.Evaluate(argumentList); } else { tokenReplacementValue = wildcardTokenReplacement.Evaluate(firstToken, argumentList); } } catch (Exception ex) { return(GetOriginalValueOrThrowException(this.StrictMatching, match.Value, string.Format("function exception {{" + Environment.NewLine + "{0}" + Environment.NewLine + "}}", ex.GetErrors(0)))); } if ((object)tokens == null || tokens.Length <= 0) { return(tokenReplacementValue?.ToString() ?? string.Empty); } tokenLogicalValue = tokenReplacementValue; foreach (string token in tokens) { // only do logical lookup here if (!tokenLogicalValue.GetLogicalPropertyValue(token, out tokenLogicalValue)) { return(GetOriginalValueOrThrowException(this.StrictMatching, match.Value, string.Format("logical property expansion failed {{{0}}}", token))); } } return(tokenLogicalValue?.ToString() ?? string.Empty); }
public void ShouldExpandTokensLooseMatchingTest() { Tokenizer tokenizer; MockFactory mockFactory; IDictionary <string, ITokenReplacement> mockTokenReplacementStrategies; ITokenReplacement mockTokenReplacement; ITokenReplacement unusedTokenReplacement = null; string _unusedString = null; string[] _unusedStrings = null; string tokenizedValue; string expandedValue; string expectedValue; mockFactory = new MockFactory(); mockTokenReplacementStrategies = mockFactory.CreateInstance <IDictionary <string, ITokenReplacement> >(); mockTokenReplacement = mockFactory.CreateInstance <ITokenReplacement>(); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myValueSemanticToken"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).WillReturn("testValue"); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myFunctionSemanticToken0"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(new string[] { })).WillReturn("testValue"); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myFunctionSemanticToken1"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(new string[] { "a", })).WillReturn("testValue"); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myFunctionSemanticToken2"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(new string[] { "a", "b" })).WillReturn("testValue"); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myUnkSemanticToken"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", null), Return.Value(false)); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("myErrSemanticToken"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).Will(Throw.Exception(new Exception())); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("a"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).WillReturn(string.Empty); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("b"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).WillReturn(string.Empty); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("c"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).WillReturn(string.Empty); Expect.On(mockTokenReplacementStrategies).One.Method(x => x.TryGetValue(_unusedString, out unusedTokenReplacement)).With(new EqualMatcher("d"), new AndMatcher(new ArgumentsMatcher.OutMatcher(), new AlwaysMatcher(true, string.Empty))).Will(new SetNamedParameterAction("value", mockTokenReplacement), Return.Value(true)); Expect.On(mockTokenReplacement).One.Method(x => x.Evaluate(_unusedStrings)).With(new EqualMatcher(null)).Will(Throw.Exception(new Exception())); tokenizer = new Tokenizer(mockTokenReplacementStrategies, false); tokenizedValue = string.Empty; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = string.Empty; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...{myNoSemanticToken}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...{myNoSemanticToken}..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myValueSemanticToken}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...testValue..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myFunctionSemanticToken0()}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...testValue..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myFunctionSemanticToken1(`a`)}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...testValue..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myFunctionSemanticToken2(`a`, `b`)}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...testValue..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myUnkSemanticToken}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...${myUnkSemanticToken}..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${myErrSemanticToken}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "...${myErrSemanticToken}..."; Assert.AreEqual(expectedValue, expandedValue); tokenizedValue = "...${a}...${c}...${b}...${d}..."; expandedValue = tokenizer.ExpandTokens(tokenizedValue); expectedValue = "............${d}..."; Assert.AreEqual(expectedValue, expandedValue); Assert.IsNotNull(tokenizer.OrderedPreviousExpansionTokens); Assert.AreEqual("a,b,c,d", string.Join(",", tokenizer.OrderedPreviousExpansionTokens)); mockFactory.VerifyAllExpectationsHaveBeenMet(); }