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

pkarwasz pushed a commit to branch ScopedContext-replace-with-interface
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit e972b5c72341ca2abf1f13d4954335ceef06fa09
Author: Ralph Goers <[email protected]>
AuthorDate: Thu Apr 4 09:00:22 2024 -0700

    Revert unit test change. Correct site changes
---
 .../log4j/message/ParameterizedMapMessageTest.java |  77 ------
 .../log4j/message/ParameterizedMessageTest.java    | 303 +++++++++++++++++++++
 src/site/asciidoc/manual/extending.adoc            |  10 +-
 3 files changed, 308 insertions(+), 82 deletions(-)

diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMapMessageTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMapMessageTest.java
deleted file mode 100644
index a560570846..0000000000
--- 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMapMessageTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.logging.log4j.message;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.logging.log4j.test.ListStatusListener;
-import org.apache.logging.log4j.test.junit.UsingStatusListener;
-import org.junit.jupiter.api.Test;
-
-@UsingStatusListener
-class ParameterizedMapMessageTest {
-
-    final ListStatusListener statusListener;
-
-    ParameterizedMapMessageTest(ListStatusListener statusListener) {
-        this.statusListener = statusListener;
-    }
-
-    @Test
-    void testNoArgs() {
-        final String testMsg = "Test message {}";
-        ParameterizedMessage msg = new ParameterizedMessage(testMsg, 
(Object[]) null);
-        String result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-        final Object[] array = null;
-        msg = new ParameterizedMessage(testMsg, array, null);
-        result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-    }
-
-    @Test
-    void testZeroLength() {
-        final String testMsg = "";
-        ParameterizedMessage msg = new ParameterizedMessage(testMsg, new 
Object[] {"arg"});
-        String result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-        final Object[] array = null;
-        msg = new ParameterizedMessage(testMsg, array, null);
-        result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-    }
-
-    @Test
-    void testOneCharLength() {
-        final String testMsg = "d";
-        ParameterizedMessage msg = new ParameterizedMessage(testMsg, new 
Object[] {"arg"});
-        String result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-        final Object[] array = null;
-        msg = new ParameterizedMessage(testMsg, array, null);
-        result = msg.getFormattedMessage();
-        assertThat(result).isEqualTo(testMsg);
-    }
-
-    @Test
-    void testFormat3StringArgs() {
-        final String testMsg = "Test message {}{} {}";
-        final String[] args = {"a", "b", "c"};
-        final String result = ParameterizedMessage.format(testMsg, args);
-        assertThat(result).isEqualTo("Test message ab c");
-    }
-}
diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
new file mode 100644
index 0000000000..4bd5df91be
--- /dev/null
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ParameterizedMessageTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.logging.log4j.message;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.status.StatusData;
+import org.apache.logging.log4j.test.ListStatusListener;
+import org.apache.logging.log4j.test.junit.Mutable;
+import org.apache.logging.log4j.test.junit.SerialUtil;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+@UsingStatusListener
+class ParameterizedMessageTest {
+
+    final ListStatusListener statusListener;
+
+    ParameterizedMessageTest(ListStatusListener statusListener) {
+        this.statusListener = statusListener;
+    }
+
+    @Test
+    void testNoArgs() {
+        final String testMsg = "Test message {}";
+        ParameterizedMessage msg = new ParameterizedMessage(testMsg, 
(Object[]) null);
+        String result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+        final Object[] array = null;
+        msg = new ParameterizedMessage(testMsg, array, null);
+        result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+    }
+
+    @Test
+    void testZeroLength() {
+        final String testMsg = "";
+        ParameterizedMessage msg = new ParameterizedMessage(testMsg, new 
Object[] {"arg"});
+        String result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+        final Object[] array = null;
+        msg = new ParameterizedMessage(testMsg, array, null);
+        result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+    }
+
+    @Test
+    void testOneCharLength() {
+        final String testMsg = "d";
+        ParameterizedMessage msg = new ParameterizedMessage(testMsg, new 
Object[] {"arg"});
+        String result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+        final Object[] array = null;
+        msg = new ParameterizedMessage(testMsg, array, null);
+        result = msg.getFormattedMessage();
+        assertThat(result).isEqualTo(testMsg);
+    }
+
+    @Test
+    void testFormat3StringArgs() {
+        final String testMsg = "Test message {}{} {}";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message ab c");
+    }
+
+    @Test
+    void testFormatNullArgs() {
+        final String testMsg = "Test message {} {} {} {} {} {}";
+        final String[] args = {"a", null, "c", null, null, null};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message a null c null null null");
+    }
+
+    @Test
+    void testFormatStringArgsIgnoresSuperfluousArgs() {
+        final String testMsg = "Test message {}{} {}";
+        final String[] args = {"a", "b", "c", "unnecessary", "superfluous"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message ab c");
+    }
+
+    @Test
+    void testFormatStringArgsWithEscape() {
+        final String testMsg = "Test message \\{}{} {}";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message {}a b");
+    }
+
+    @Test
+    void testFormatStringArgsWithTrailingEscape() {
+        final String testMsg = "Test message {}{} {}\\";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message ab c\\");
+    }
+
+    @Test
+    void testFormatStringArgsWithTrailingText() {
+        final String testMsg = "Test message {}{} {}Text";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message ab cText");
+    }
+
+    @Test
+    void testFormatStringArgsWithTrailingEscapedEscape() {
+        final String testMsg = "Test message {}{} {}\\\\";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message ab c\\");
+    }
+
+    @Test
+    void testFormatStringArgsWithEscapedEscape() {
+        final String testMsg = "Test message \\\\{}{} {}";
+        final String[] args = {"a", "b", "c"};
+        final String result = ParameterizedMessage.format(testMsg, args);
+        assertThat(result).isEqualTo("Test message \\ab c");
+    }
+
+    @Test
+    void testSafeWithMutableParams() { // LOG4J2-763
+        final String testMsg = "Test message {}";
+        final Mutable param = new Mutable().set("abc");
+        final ParameterizedMessage msg = new ParameterizedMessage(testMsg, 
param);
+
+        // modify parameter before calling msg.getFormattedMessage
+        param.set("XYZ");
+        final String actual = msg.getFormattedMessage();
+        assertThat(actual).isEqualTo("Test message XYZ").as("Should use 
current param value");
+
+        // modify parameter after calling msg.getFormattedMessage
+        param.set("000");
+        final String after = msg.getFormattedMessage();
+        assertThat(after).isEqualTo("Test message XYZ").as("Should not change 
after rendered once");
+    }
+
+    static Stream<Object> testSerializable() {
+        @SuppressWarnings("EqualsHashCode")
+        class NonSerializable {
+            @Override
+            public boolean equals(final Object other) {
+                return other instanceof NonSerializable; // a very lenient 
equals()
+            }
+        }
+        return Stream.of(
+                "World",
+                new NonSerializable(),
+                new BigDecimal("123.456"),
+                // LOG4J2-3680
+                new RuntimeException(),
+                null);
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void testSerializable(final Object arg) {
+        final Message expected = new ParameterizedMessage("Hello {}!", arg);
+        final Message actual = 
SerialUtil.deserialize(SerialUtil.serialize(expected));
+        assertThat(actual).isInstanceOf(ParameterizedMessage.class);
+        
assertThat(actual.getFormattedMessage()).isEqualTo(expected.getFormattedMessage());
+    }
+
+    /**
+     * In this test cases, constructed the following scenarios: <br>
+     * <p>
+     * 1. The arguments contains an exception, and the count of placeholder is 
equal to arguments include exception. <br>
+     * 2. The arguments contains an exception, and the count of placeholder is 
equal to arguments except exception.<br>
+     * All of these should not logged in status logger.
+     * </p>
+     *
+     * @return Streams
+     */
+    static Stream<Object[]> testCasesWithExceptionArgsButNoWarn() {
+        return Stream.of(
+                new Object[] {
+                    "with exception {} {}",
+                    new Object[] {"a", new RuntimeException()},
+                    "with exception a java.lang.RuntimeException"
+                },
+                new Object[] {
+                    "with exception {} {}", new Object[] {"a", "b", new 
RuntimeException()}, "with exception a b"
+                });
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCasesWithExceptionArgsButNoWarn")
+    void formatToWithExceptionButNoWarn(final String pattern, final Object[] 
args, final String expected) {
+        final ParameterizedMessage message = new ParameterizedMessage(pattern, 
args);
+        final StringBuilder buffer = new StringBuilder();
+        message.formatTo(buffer);
+        assertThat(buffer.toString()).isEqualTo(expected);
+        final List<StatusData> statusDataList = 
statusListener.getStatusData().collect(Collectors.toList());
+        assertThat(statusDataList).hasSize(0);
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCasesWithExceptionArgsButNoWarn")
+    void formatWithExceptionButNoWarn(final String pattern, final Object[] 
args, final String expected) {
+        final String message = ParameterizedMessage.format(pattern, args);
+        assertThat(message).isEqualTo(expected);
+        final List<StatusData> statusDataList = 
statusListener.getStatusData().collect(Collectors.toList());
+        assertThat(statusDataList).hasSize(0);
+    }
+
+    /**
+     * In this test cases, constructed the following scenarios: <br>
+     * <p>
+     * 1. The placeholders are greater than the count of arguments. <br>
+     * 2. The placeholders are less than the count of arguments. <br>
+     * 3. The arguments contains an exception, and the placeholder is greater 
than normal arguments. <br>
+     * 4. The arguments contains an exception, and the placeholder is less 
than the arguments.<br>
+     * All of these should logged in status logger with WARN level.
+     * </p>
+     *
+     * @return streams
+     */
+    static Stream<Object[]> testCasesForInsufficientFormatArgs() {
+        return Stream.of(
+                new Object[] {"more {} {}", 2, new Object[] {"a"}, "more a 
{}"},
+                new Object[] {"more {} {} {}", 3, new Object[] {"a"}, "more a 
{} {}"},
+                new Object[] {"less {}", 1, new Object[] {"a", "b"}, "less a"},
+                new Object[] {"less {} {}", 2, new Object[] {"a", "b", "c"}, 
"less a b"},
+                new Object[] {
+                    "more throwable {} {} {}",
+                    3,
+                    new Object[] {"a", new RuntimeException()},
+                    "more throwable a java.lang.RuntimeException {}"
+                },
+                new Object[] {
+                    "less throwable {}", 1, new Object[] {"a", "b", new 
RuntimeException()}, "less throwable a"
+                });
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCasesForInsufficientFormatArgs")
+    void formatToShouldWarnOnInsufficientArgs(
+            final String pattern, final int placeholderCount, final Object[] 
args, final String expected) {
+        final int argCount = args == null ? 0 : args.length;
+        verifyFormattingFailureOnInsufficientArgs(pattern, placeholderCount, 
argCount, expected, () -> {
+            final ParameterizedMessage message = new 
ParameterizedMessage(pattern, args);
+            final StringBuilder buffer = new StringBuilder();
+            message.formatTo(buffer);
+            return buffer.toString();
+        });
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCasesForInsufficientFormatArgs")
+    void formatShouldWarnOnInsufficientArgs(
+            final String pattern, final int placeholderCount, final Object[] 
args, final String expected) {
+        final int argCount = args == null ? 0 : args.length;
+        verifyFormattingFailureOnInsufficientArgs(
+                pattern, placeholderCount, argCount, expected, () -> 
ParameterizedMessage.format(pattern, args));
+    }
+
+    private void verifyFormattingFailureOnInsufficientArgs(
+            final String pattern,
+            final int placeholderCount,
+            final int argCount,
+            final String expected,
+            final Supplier<String> formattedMessageSupplier) {
+
+        // Verify the formatted message
+        final String formattedMessage = formattedMessageSupplier.get();
+        assertThat(formattedMessage).isEqualTo(expected);
+
+        // Verify the status logger warn
+        final List<StatusData> statusDataList = 
statusListener.getStatusData().collect(Collectors.toList());
+        assertThat(statusDataList).hasSize(1);
+        final StatusData statusData = statusDataList.get(0);
+        assertThat(statusData.getLevel()).isEqualTo(Level.WARN);
+        assertThat(statusData.getMessage().getFormattedMessage())
+                .isEqualTo(
+                        "found %d argument placeholders, but provided %d for 
pattern `%s`",
+                        placeholderCount, argCount, pattern);
+        assertThat(statusData.getThrowable()).isNull();
+    }
+}
diff --git a/src/site/asciidoc/manual/extending.adoc 
b/src/site/asciidoc/manual/extending.adoc
index 03e84c26e7..53dd637a7e 100644
--- a/src/site/asciidoc/manual/extending.adoc
+++ b/src/site/asciidoc/manual/extending.adoc
@@ -587,14 +587,14 @@ ListAppender list2 = 
ListAppender.newBuilder().setName("List1").setEntryPerNewLi
 [#Custom_ContextDataProvider]
 == Custom ContextDataProvider
 
-The 
link:../log4j-api/apidocs/org/apache/logging/log4j/spi/ContextDataProvider.html[`ContextDataProvider`]
-(introduced in Log4j 2.13.2 and moved to log4j-api in 2.24.0) is an interface 
applications and libraries
+The 
link:../log4j-core/apidocs/org/apache/logging/log4j/core/util/ContextDataProvider.html[`ContextDataProvider`]
+(introduced in Log4j 2.13.2) is an interface applications and libraries
 can use to inject additional key-value pairs into the LogEvent's context data.
 Log4j itself adds the ThreadContext data to the LogEvent using 
-`org.apache.logging.log4j.spi.ThreadContextDataProvider`. Custom 
implementations
-should implement the `org.apache.logging.log4j.spi.ContextDataProvider` 
interface and
+`org.apache.logging.log4j.core.impl.ThreadContextDataProvider`. Custom 
implementations
+should implement the `org.apache.logging.log4j.core.util.ContextDataProvider` 
interface and
 declare it as a service by defining the implmentation class in a file named
-`META-INF/services/org.apache.logging.log4j.spi.ContextDataProvider`.
+`META-INF/services/org.apache.logging.log4j.core.util.ContextDataProvider`.
 
 == Custom ThreadContextMap implementations
 

Reply via email to