Skip to content

Commit 0153e4d

Browse files
committed
Use proper formatter for java.time classes
Prevents "java.lang.IllegalArgumentException: Cannot format given Object as a Date" during persisting of logs. Add tests with some help from Claude This closes #884
1 parent caf80c5 commit 0153e4d

2 files changed

Lines changed: 124 additions & 6 deletions

File tree

accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/PersistableInstallationLogger.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
import java.io.IOException;
1919
import java.io.PrintWriter;
2020
import java.io.StringWriter;
21-
import java.sql.Timestamp;
22-
import java.text.DateFormat;
2321
import java.text.NumberFormat;
24-
import java.text.SimpleDateFormat;
2522
import java.time.ZonedDateTime;
23+
import java.time.format.DateTimeFormatter;
2624
import java.util.Collection;
2725
import java.util.Date;
2826
import java.util.HashSet;
@@ -79,7 +77,7 @@ public class PersistableInstallationLogger implements InstallationLogger, Instal
7977

8078
private int missingParentPathsForInitialContent = 0;
8179

82-
private DateFormat timestampFormat = new SimpleDateFormat("HH:mm:ss.SSS");
80+
private DateTimeFormatter timestampFormat = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
8381

8482
private final Collection<BiConsumer<InstallationLogLevel, String>> listeners;
8583
private final Collection<Consumer<Boolean>> finishListeners;
@@ -265,8 +263,7 @@ private String getMessageString(Set<HistoryEntry> messageHistorySet) {
265263
StringBuilder sb = new StringBuilder();
266264
if (!messageHistorySet.isEmpty()) {
267265
for (HistoryEntry entry : messageHistorySet) {
268-
sb.append(EOL + timestampFormat.format(entry.getDate()) + ": "
269-
+ entry.getMessage());
266+
sb.append(EOL).append((entry.getDate().format(timestampFormat))).append(": ").append(entry.getMessage());
270267
}
271268
}
272269
return sb.toString();
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package biz.netcentric.cq.tools.actool.history.impl;
2+
3+
/*-
4+
* #%L
5+
* Access Control Tool Bundle
6+
* %%
7+
* Copyright (C) 2015 - 2024 Cognizant Netcentric
8+
* %%
9+
* This program and the accompanying materials are made
10+
* available under the terms of the Eclipse Public License 2.0
11+
* which is available at https://www.eclipse.org/legal/epl-2.0/
12+
*
13+
* SPDX-License-Identifier: EPL-2.0
14+
* #L%
15+
*/
16+
17+
import static org.junit.jupiter.api.Assertions.*;
18+
19+
import java.util.regex.Pattern;
20+
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
import org.slf4j.helpers.NOPLogger;
24+
25+
class PersistableInstallationLoggerTest {
26+
27+
private PersistableInstallationLogger logger;
28+
29+
@BeforeEach
30+
void setUp() {
31+
logger = new PersistableInstallationLogger();
32+
}
33+
34+
@Test
35+
void testGetVerboseMessageHistoryContainsAllMessageTypes() {
36+
logger.addMessage(NOPLogger.NOP_LOGGER, "regular message");
37+
logger.addWarning(NOPLogger.NOP_LOGGER, "a warning");
38+
logger.addVerboseMessage(NOPLogger.NOP_LOGGER, "verbose detail");
39+
logger.addError(NOPLogger.NOP_LOGGER, "an error", null);
40+
41+
String verbose = logger.getVerboseMessageHistory();
42+
43+
assertTrue(verbose.contains("regular message"), "verbose history should contain regular messages");
44+
assertTrue(verbose.contains("a warning"), "verbose history should contain warnings");
45+
assertTrue(verbose.contains("verbose detail"), "verbose history should contain verbose messages");
46+
assertTrue(verbose.contains("an error"), "verbose history should contain errors");
47+
}
48+
49+
@Test
50+
void testGetVerboseMessageHistoryContainsVerboseMessagesAbsentFromMessageHistory() {
51+
logger.addMessage(NOPLogger.NOP_LOGGER, "regular message");
52+
logger.addVerboseMessage(NOPLogger.NOP_LOGGER, "verbose only detail");
53+
54+
String messageHistory = logger.getMessageHistory();
55+
String verboseHistory = logger.getVerboseMessageHistory();
56+
57+
assertFalse(messageHistory.contains("verbose only detail"),
58+
"non-verbose message history should NOT contain verbose messages");
59+
assertTrue(verboseHistory.contains("verbose only detail"),
60+
"verbose message history should contain verbose messages");
61+
assertTrue(verboseHistory.contains("regular message"),
62+
"verbose message history should also contain regular messages");
63+
}
64+
65+
@Test
66+
void testGetVerboseMessageHistoryWithExceptionIncludesStackTrace() {
67+
RuntimeException ex = new RuntimeException("something went wrong");
68+
logger.addError(NOPLogger.NOP_LOGGER, "error with exception", ex);
69+
70+
String verboseHistory = logger.getVerboseMessageHistory();
71+
72+
assertTrue(verboseHistory.contains("error with exception"),
73+
"verbose history should contain the error message");
74+
assertTrue(verboseHistory.contains("RuntimeException"),
75+
"verbose history should contain the exception stack trace");
76+
}
77+
78+
@Test
79+
void testGetVerboseMessageHistoryEmptyWhenNoMessages() {
80+
String verboseHistory = logger.getVerboseMessageHistory();
81+
assertTrue(verboseHistory.isEmpty(), "verbose history should be empty when no messages have been added");
82+
}
83+
84+
@Test
85+
void testGetVerboseMessageHistoryTimestampPrefix() {
86+
logger.addMessage(NOPLogger.NOP_LOGGER, "timed message");
87+
logger.addVerboseMessage(NOPLogger.NOP_LOGGER, "timed verbose");
88+
89+
String verboseHistory = logger.getVerboseMessageHistory();
90+
91+
// Each entry is formatted as: \nHH:mm:ss.SSS: <message>
92+
Pattern timestampPattern = Pattern.compile("\\d{2}:\\d{2}:\\d{2}\\.\\d{3}: ");
93+
assertTrue(timestampPattern.matcher(verboseHistory).find(),
94+
"each entry should be prefixed with a timestamp in HH:mm:ss.SSS format");
95+
96+
// Verify every line that contains a known message has the timestamp prefix
97+
for (String line : verboseHistory.split(PersistableInstallationLogger.EOL)) {
98+
if (line.isEmpty()) {
99+
continue;
100+
}
101+
assertTrue(timestampPattern.matcher(line).find(),
102+
"line should start with HH:mm:ss.SSS timestamp: " + line);
103+
}
104+
}
105+
106+
@Test
107+
void testGetVerboseMessageHistoryMessagesAreOrderedByIndex() {
108+
logger.addMessage(NOPLogger.NOP_LOGGER, "first");
109+
logger.addVerboseMessage(NOPLogger.NOP_LOGGER, "second");
110+
logger.addMessage(NOPLogger.NOP_LOGGER, "third");
111+
112+
String verboseHistory = logger.getVerboseMessageHistory();
113+
114+
int firstPos = verboseHistory.indexOf("first");
115+
int secondPos = verboseHistory.indexOf("second");
116+
int thirdPos = verboseHistory.indexOf("third");
117+
118+
assertTrue(firstPos < secondPos, "first message should appear before second");
119+
assertTrue(secondPos < thirdPos, "second message should appear before third");
120+
}
121+
}

0 commit comments

Comments
 (0)