This is an automated email from the ASF dual-hosted git repository.

tabish pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-protonj2.git


The following commit(s) were added to refs/heads/main by this push:
     new 9eaf5e00 PROTON-2845 Improve output of failed match when validating 
messages
9eaf5e00 is described below

commit 9eaf5e00e4c3953c526f00ac0df2980859c7b5a3
Author: Timothy Bish <tabish...@gmail.com>
AuthorDate: Wed Aug 7 18:24:45 2024 -0400

    PROTON-2845 Improve output of failed match when validating messages
    
    When checking on scripted transfer payload contents the output should
    provide more information to make it clear what failed in the contents
    matching.
---
 .../matchers/transport/TransferMessageMatcher.java |  38 +--
 .../protonj2/test/driver/util/StringUtils.java     | 327 +++++++++++++++++++++
 2 files changed, 348 insertions(+), 17 deletions(-)

diff --git 
a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/matchers/transport/TransferMessageMatcher.java
 
b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/matchers/transport/TransferMessageMatcher.java
index 25cb5a80..decd74ff 100644
--- 
a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/matchers/transport/TransferMessageMatcher.java
+++ 
b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/matchers/transport/TransferMessageMatcher.java
@@ -33,6 +33,7 @@ import 
org.apache.qpid.protonj2.test.driver.matchers.types.EncodedAmqpSequenceMa
 import 
org.apache.qpid.protonj2.test.driver.matchers.types.EncodedAmqpTypeMatcher;
 import 
org.apache.qpid.protonj2.test.driver.matchers.types.EncodedAmqpValueMatcher;
 import org.apache.qpid.protonj2.test.driver.matchers.types.EncodedDataMatcher;
+import org.apache.qpid.protonj2.test.driver.util.StringUtils;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.StringDescription;
@@ -88,8 +89,9 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 bytesConsumed += 
headersMatcher.getInnerMatcher().verify(receivedSlice.slice());
                 receivedSlice.position(bytesConsumed);
             } catch (Throwable t) {
-                headerMatcherFailureDescription = "\nActual encoded form of 
remaining bytes passed to MessageHeaderMatcher: " + receivedSlice;
-                headerMatcherFailureDescription += "\nMessageHeaderMatcher 
generated throwable: " + t;
+                headerMatcherFailureDescription = "\nBuffer of bytes passed to 
Header Matcher: " + receivedSlice;
+                headerMatcherFailureDescription += "\nActual encoded form of 
remaining bytes passed: " + StringUtils.toQuotedString(receivedSlice);
+                headerMatcherFailureDescription += "\nHeader Matcher generated 
throwable: " + t.getMessage();
 
                 return false;
             }
@@ -101,9 +103,9 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 bytesConsumed += 
deliveryAnnotationsMatcher.getInnerMatcher().verify(receivedSlice.slice());
                 receivedSlice.position(bytesConsumed);
             } catch (Throwable t) {
-                deliveryAnnotationsMatcherFailureDescription = "\nActual 
encoded form of remaining bytes passed " +
-                                                               "to 
DeliveryAnnotationsMatcher: " + receivedSlice;
-                deliveryAnnotationsMatcherFailureDescription += 
"\nDeliveryAnnotationsMatcher generated throwable: " + t;
+                deliveryAnnotationsMatcherFailureDescription = "\nBuffer of 
bytes passed to Delivery Annotations Matcher: " + receivedSlice;
+                deliveryAnnotationsMatcherFailureDescription += "\nActual 
encoded form of remaining bytes passed: " + 
StringUtils.toQuotedString(receivedSlice);
+                deliveryAnnotationsMatcherFailureDescription += "\nDelivery 
Annotations Matcher generated throwable: " + t.getMessage();
 
                 return false;
             }
@@ -115,9 +117,9 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 bytesConsumed += 
messageAnnotationsMatcher.getInnerMatcher().verify(receivedSlice.slice());
                 receivedSlice.position(bytesConsumed);
             } catch (Throwable t) {
-                messageAnnotationsMatcherFailureDescription = "\nActual 
encoded form of remaining bytes passed to " +
-                                                              
"MessageAnnotationsMatcher: " + receivedSlice;
-                messageAnnotationsMatcherFailureDescription += 
"\nMessageAnnotationsMatcher generated throwable: " + t;
+                messageAnnotationsMatcherFailureDescription = "\nBuffer of 
bytes passed to Message Annotations Matcher: " + receivedSlice;
+                messageAnnotationsMatcherFailureDescription += "\nActual 
encoded form of remaining bytes passed: " + 
StringUtils.toQuotedString(receivedSlice);
+                messageAnnotationsMatcherFailureDescription += "\nMessage 
Annotations Matcher generated throwable: " + t.getMessage();
 
                 return false;
             }
@@ -129,9 +131,9 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 bytesConsumed += 
propertiesMatcher.getInnerMatcher().verify(receivedSlice.slice());
                 receivedSlice.position(bytesConsumed);
             } catch (Throwable t) {
-                propertiesMatcherFailureDescription = "\nActual encoded form 
of remaining bytes passed to " +
-                                                      "PropertiesMatcher: " + 
receivedSlice;
-                propertiesMatcherFailureDescription += "\nPropertiesMatcher 
generated throwable: " + t;
+                propertiesMatcherFailureDescription = "\nBuffer of bytes 
passed to Properties Matcher: " + receivedSlice;
+                propertiesMatcherFailureDescription += "\nActual encoded form 
of remaining bytes passed: " + StringUtils.toQuotedString(receivedSlice);
+                propertiesMatcherFailureDescription += "\nProperties Matcher 
generated throwable: " + t.getMessage();
 
                 return false;
             }
@@ -143,9 +145,9 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 bytesConsumed += 
applicationPropertiesMatcher.getInnerMatcher().verify(receivedSlice.slice());
                 receivedSlice.position(bytesConsumed);
             } catch (Throwable t) {
-                applicationPropertiesMatcherFailureDescription = "\nActual 
encoded form of remaining bytes passed to " +
-                                                                 
"ApplicationPropertiesMatcher: " + receivedSlice;
-                applicationPropertiesMatcherFailureDescription += 
"\nApplicationPropertiesMatcher generated throwable: " + t;
+                applicationPropertiesMatcherFailureDescription = "\nBuffer of 
bytes passed to Application Properties Matcher: " + receivedSlice;
+                applicationPropertiesMatcherFailureDescription += "\nActual 
encoded form of remaining bytes passed: " + 
StringUtils.toQuotedString(receivedSlice);
+                applicationPropertiesMatcherFailureDescription += 
"\nApplication Properties Matcher generated throwable: " + t.getMessage();
 
                 return false;
             }
@@ -161,9 +163,11 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
                 if (!contentMatches) {
                     Description desc = new StringDescription();
                     msgContentMatcher.describeTo(desc);
-                    msgContentMatcher.describeMismatch(receivedSlice, desc);
+                    msgContentMatcher.describeMismatch(slicedMsgContext, desc);
 
-                    msgContentMatcherFailureDescription = 
"\nMessageContentMatcher mismatch Description:";
+                    msgContentMatcherFailureDescription = "\nBuffer of bytes 
passed to message contents Matcher: " + slicedMsgContext;
+                    msgContentMatcherFailureDescription += "\nActual encoded 
form of remaining bytes passed: " + StringUtils.toQuotedString(receivedSlice);
+                    msgContentMatcherFailureDescription += 
"\nMessageContentMatcher mismatch Description:";
                     msgContentMatcherFailureDescription += desc.toString();
 
                     return false;
@@ -181,7 +185,7 @@ public class TransferMessageMatcher extends 
TypeSafeMatcher<ByteBuffer> {
             } catch (Throwable t) {
                 footerMatcherFailureDescription = "\nActual encoded form of 
remaining bytes passed to " +
                                                   "FooterMatcher: " + 
receivedSlice;
-                footerMatcherFailureDescription += "\nFooterMatcher generated 
throwable: " + t;
+                footerMatcherFailureDescription += "\nFooterMatcher generated 
throwable: " + t.getMessage();
 
                 return false;
             }
diff --git 
a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/util/StringUtils.java
 
b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/util/StringUtils.java
new file mode 100644
index 00000000..ee5ac18a
--- /dev/null
+++ 
b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/util/StringUtils.java
@@ -0,0 +1,327 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.protonj2.test.driver.util;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.qpid.protonj2.test.driver.codec.primitives.Binary;
+import org.apache.qpid.protonj2.test.driver.codec.primitives.Symbol;
+
+/**
+ * Set of {@link String} utilities used in the proton code.
+ */
+public class StringUtils {
+
+    private static final int DEFAULT_QUOTED_STRING_LIMIT = 64;
+
+    /**
+     * Converts the given String[] into a Symbol[] array.
+     *
+     * @param stringArray
+     *                 The given String[] to convert.
+     *
+     * @return a new Symbol array that contains Symbol versions of the input 
Strings.
+     */
+    public static Symbol[] toSymbolArray(String[] stringArray) {
+        Symbol[] result = null;
+
+        if (stringArray != null) {
+            result = new Symbol[stringArray.length];
+            for (int i = 0; i < stringArray.length; ++i) {
+                result[i] = Symbol.valueOf(stringArray[i]);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given Symbol[] into a String[] array.
+     *
+     * @param symbolArray
+     *                 The given Symbol[] to convert.
+     *
+     * @return a new String array that contains String versions of the input 
Symbol.
+     */
+    public static String[] toStringArray(Symbol[] symbolArray) {
+        String[] result = null;
+
+        if (symbolArray != null) {
+            result = new String[symbolArray.length];
+            for (int i = 0; i < symbolArray.length; ++i) {
+                result[i] = symbolArray[i].toString();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given String keyed {@link Map} into a matching Symbol 
keyed {@link Map}.
+     *
+     * @param stringsMap
+     *                 The given String keyed {@link Map} to convert.
+     *
+     * @return a new Symbol keyed {@link Map} that contains Symbol versions of 
the input String keys.
+     */
+    public static Map<Symbol, Object> toSymbolKeyedMap(Map<String, Object> 
stringsMap) {
+        final Map<Symbol, Object> result;
+
+        if (stringsMap != null) {
+            result = new HashMap<>(stringsMap.size());
+            stringsMap.forEach((key, value) -> {
+                result.put(Symbol.valueOf(key), value);
+            });
+        } else {
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given Symbol keyed {@link Map} into a matching String 
keyed {@link Map}.
+     *
+     * @param symbolMap
+     *                 The given String keyed {@link Map} to convert.
+     *
+     * @return a new String keyed {@link Map} that contains String versions of 
the input Symbol keys.
+     */
+    public static Map<String, Object> toStringKeyedMap(Map<Symbol, Object> 
symbolMap) {
+        Map<String, Object> result;
+
+        if (symbolMap != null) {
+            result = new LinkedHashMap<>(symbolMap.size());
+            symbolMap.forEach((key, value) -> {
+                result.put(key.toString(), value);
+            });
+        } else {
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given String {@link Collection} into a Symbol array.
+     *
+     * @param stringsSet
+     *                 The given String {@link Collection} to convert.
+     *
+     * @return a new Symbol array that contains String versions of the input 
Symbols.
+     */
+    public static Symbol[] toSymbolArray(Collection<String> stringsSet) {
+        final Symbol[] result;
+
+        if (stringsSet != null) {
+            result = new Symbol[stringsSet.size()];
+            int index = 0;
+            for (String entry : stringsSet) {
+                result[index++] = Symbol.valueOf(entry);
+            }
+        } else {
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given String {@link Collection} into a matching Symbol 
{@link Set}.
+     *
+     * @param stringsSet
+     *                 The given String {@link Collection} to convert.
+     *
+     * @return a new Symbol {@link Set} that contains String versions of the 
input Symbols.
+     */
+    public static Set<Symbol> toSymbolSet(Collection<String> stringsSet) {
+        final Set<Symbol> result;
+
+        if (stringsSet != null) {
+            result = new LinkedHashSet<>(stringsSet.size());
+            stringsSet.forEach((entry) -> {
+                result.add(Symbol.valueOf(entry));
+            });
+        } else {
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the given Symbol array into a matching String {@link Set}.
+     *
+     * @param symbols
+     *                 The given Symbol array to convert.
+     *
+     * @return a new String {@link Set} that contains String versions of the 
input Symbols.
+     */
+    public static Set<String> toStringSet(Symbol[] symbols) {
+        Set<String> result;
+
+        if (symbols != null) {
+            result = new LinkedHashSet<>(symbols.length);
+            for (Symbol symbol : symbols) {
+                result.add(symbol.toString());
+            }
+        } else {
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the Binary to a quoted string using a default max length 
before truncation value and
+     * appends a truncation indication if the string required truncation.
+     *
+     * @param buffer
+     *        the {@link Binary} to convert into String format.
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final Binary buffer) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, true);
+    }
+
+    /**
+     * Converts the Binary to a quoted string using a default max length 
before truncation value.
+     *
+     * @param buffer
+     *        the {@link Binary} to convert into String format.
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in 
the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final Binary buffer, final boolean 
appendIfTruncated) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, 
appendIfTruncated);
+    }
+
+    /**
+     * Converts the Binary to a quoted string.
+     *
+     * @param buffer
+     *        the {@link Binary} to convert into String format.
+     * @param stringLength
+     *        the maximum length of stringified content (excluding the quotes, 
and truncated indicator)
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in 
the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final Binary buffer, final int 
stringLength, final boolean appendIfTruncated) {
+        if (buffer == null) {
+            return "\"\"";
+        } else {
+            return toQuotedString(buffer.asByteBuffer(), stringLength, 
appendIfTruncated);
+        }
+    }
+
+    /**
+     * Converts the ProtonBuffer to a quoted string using a default max length 
before truncation value and
+     * appends a truncation indication if the string required truncation.
+     *
+     * @param buffer
+     *        the {@link ByteBuffer} to convert into String format.
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final ByteBuffer buffer) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, true);
+    }
+
+    /**
+     * Converts the ProtonBuffer to a quoted string using a default max length 
before truncation value.
+     *
+     * @param buffer
+     *        the {@link ByteBuffer} to convert into String format.
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in 
the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final ByteBuffer buffer, final boolean 
appendIfTruncated) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, 
appendIfTruncated);
+    }
+
+    /**
+     * Converts the ProtonBuffer to a quoted string.
+     *
+     * @param buffer
+     *        the {@link ByteBuffer} to convert into String format.
+     * @param stringLength
+     *        the maximum length of stringified content (excluding the quotes, 
and truncated indicator)
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in 
the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final ByteBuffer buffer, final int 
stringLength, final boolean appendIfTruncated) {
+        if (buffer == null) {
+            return "\"\"";
+        }
+
+        StringBuilder str = new StringBuilder();
+        str.append("\"");
+
+        final int byteToRead = buffer.remaining();
+        int size = 0;
+        boolean truncated = false;
+
+        for (int i = 0; i < byteToRead; ++i) {
+            byte c = buffer.get(i);
+
+            if (c > 31 && c < 127 && c != '\\') {
+                if (size + 1 <= stringLength) {
+                    size += 1;
+                    str.append((char) c);
+                } else {
+                    truncated = true;
+                    break;
+                }
+            } else {
+                if (size + 4 <= stringLength) {
+                    size += 4;
+                    str.append(String.format("\\x%02x", c));
+                } else {
+                    truncated = true;
+                    break;
+                }
+            }
+        }
+
+        str.append("\"");
+
+        if (truncated && appendIfTruncated) {
+            str.append("...(truncated)");
+        }
+
+        return str.toString();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to