From 5ac643368ddeb928af0e7cf8705b52b9beb31053 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 30 Dec 2019 14:53:22 -0500 Subject: [PATCH] [LANG-1506] Allow a StopWatch to carry an optional message. --- src/changes/changes.xml | 1 + .../apache/commons/lang3/time/StopWatch.java | 50 ++++++++-- .../commons/lang3/time/StopWatchTest.java | 92 ++++++++++++++++++- 3 files changed, 131 insertions(+), 12 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d6983ccfc..a204b0791 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -88,6 +88,7 @@ The type attribute can be add,update,fix,remove. Functions Javadoc #466. Add factory methods to Pair classes with Map.Entry input. #454. Add StopWatch convenience APIs to format times and create a simple instance. + Allow a StopWatch to carry an optional message. diff --git a/src/main/java/org/apache/commons/lang3/time/StopWatch.java b/src/main/java/org/apache/commons/lang3/time/StopWatch.java index 2b6a7ed44..3be754526 100644 --- a/src/main/java/org/apache/commons/lang3/time/StopWatch.java +++ b/src/main/java/org/apache/commons/lang3/time/StopWatch.java @@ -17,8 +17,11 @@ package org.apache.commons.lang3.time; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; + /** *

* {@code StopWatch} provides a convenient API for timings. @@ -184,6 +187,13 @@ public static StopWatch createStarted() { return sw; } + /** + * A message for string presentation. + * + * @since 3.10 + */ + private final String message; + /** * The current running state of the StopWatch. */ @@ -217,7 +227,18 @@ public static StopWatch createStarted() { *

*/ public StopWatch() { - super(); + this(null); + } + + /** + *

+ * Constructor. + *

+ * @param message A message for string presentation. + * @since 3.10 + */ + public StopWatch(final String message) { + this.message = message; } /** @@ -240,6 +261,16 @@ public String formatTime() { return DurationFormatUtils.formatDurationHMS(getTime()); } + /** + * Gets the message for string presentation. + * + * @return the message for string presentation. + * @since 3.10 + */ + public String getMessage() { + return message; + } + /** *

* Gets the time on the stopwatch in nanoseconds. @@ -264,7 +295,6 @@ public long getNanoTime() { throw new RuntimeException("Illegal running state has occurred."); } - /** *

* Gets the split time on the stopwatch in nanoseconds. @@ -409,7 +439,6 @@ public void reset() { this.runningState = State.UNSTARTED; this.splitState = SplitState.UNSPLIT; } - /** *

* Resumes the stopwatch after a suspend. @@ -430,6 +459,7 @@ public void resume() { this.startTime += System.nanoTime() - this.stopTime; this.runningState = State.RUNNING; } + /** *

* Splits the time. @@ -524,14 +554,17 @@ public void suspend() { *

* *

- * The format used is ISO 8601-like, hours:minutes:seconds.milliseconds. + * The format used is ISO 8601-like, [message ]hours:minutes:seconds.milliseconds. *

* * @return the split time as a String * @since 2.1 + * @since 3.10 Returns the prefix {@code "message "} if the message is set. */ public String toSplitString() { - return DurationFormatUtils.formatDurationHMS(getSplitTime()); + final String msgStr = Objects.toString(message, StringUtils.EMPTY); + final String formattedTime = formatSplitTime(); + return msgStr.isEmpty() ? formattedTime : msgStr + StringUtils.SPACE + formattedTime; } /** @@ -540,14 +573,17 @@ public String toSplitString() { *

* *

- * The format used is ISO 8601-like, hours:minutes:seconds.milliseconds. + * The format used is ISO 8601-like, [message ]hours:minutes:seconds.milliseconds. *

* * @return the time as a String + * @since 3.10 Returns the prefix {@code "message "} if the message is set. */ @Override public String toString() { - return DurationFormatUtils.formatDurationHMS(getTime()); + final String msgStr = Objects.toString(message, StringUtils.EMPTY); + final String formattedTime = formatTime(); + return msgStr.isEmpty() ? formattedTime : msgStr + StringUtils.SPACE + formattedTime; } /** diff --git a/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java b/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java index d88eca657..61e9792fd 100644 --- a/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java +++ b/src/test/java/org/apache/commons/lang3/time/StopWatchTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -32,6 +33,11 @@ */ public class StopWatchTest { + private static final String MESSAGE = "Baking cookies"; + private static final int MIN_SLEEP_MILLISECONDS = 20; + private static final String ZERO_HOURS_PREFIX = "00:"; + private static final String ZERO_TIME_ELAPSED = "00:00:00.000"; + /** *

* Creates a suspended StopWatch object which appears to have elapsed @@ -148,15 +154,37 @@ public void testBooleanStates() { @Test public void testFormatSplitTime() throws InterruptedException { final StopWatch watch = StopWatch.createStarted(); - Thread.sleep(20); + Thread.sleep(MIN_SLEEP_MILLISECONDS); watch.split(); - assertNotEquals("00:00:00.000", watch.formatSplitTime()); + final String formatSplitTime = watch.formatSplitTime(); + assertNotEquals(ZERO_TIME_ELAPSED, formatSplitTime); + assertTrue(formatSplitTime.startsWith(ZERO_HOURS_PREFIX)); + } + + @Test + public void testFormatSplitTimeWithMessage() throws InterruptedException { + final StopWatch watch = new StopWatch(MESSAGE); + watch.start(); + Thread.sleep(MIN_SLEEP_MILLISECONDS); + watch.split(); + final String formatSplitTime = watch.formatSplitTime(); + assertFalse(formatSplitTime.startsWith(MESSAGE), formatSplitTime); + assertTrue(formatSplitTime.startsWith(ZERO_HOURS_PREFIX)); } @Test public void testFormatTime() { final StopWatch watch = StopWatch.create(); - assertEquals("00:00:00.000", watch.formatTime()); + final String formatTime = watch.formatTime(); + assertEquals(ZERO_TIME_ELAPSED, formatTime); + assertTrue(formatTime.startsWith(ZERO_HOURS_PREFIX)); + } + + @Test + public void testFormatTimeWithMessage() { + final StopWatch watch = new StopWatch(MESSAGE); + final String formatTime = watch.formatTime(); + assertFalse(formatTime.startsWith(MESSAGE), formatTime); } @Test @@ -199,6 +227,17 @@ public void testLang315() { assertEquals(suspendTime, totalTime); } + @Test + public void testMessage() { + assertNull(StopWatch.create().getMessage()); + final StopWatch stopWatch = new StopWatch(MESSAGE); + assertEquals(MESSAGE, stopWatch.getMessage()); + assertTrue(stopWatch.toString().startsWith(MESSAGE)); + stopWatch.start(); + stopWatch.split(); + assertTrue(stopWatch.toSplitString().startsWith(MESSAGE)); + } + @Test public void testStopWatchGetWithTimeUnit() { // Create a mock StopWatch with a time of 2:59:01.999 @@ -214,7 +253,6 @@ public void testStopWatchGetWithTimeUnit() { assertEquals(10741999L, watch.getTime(TimeUnit.MILLISECONDS)); } - //----------------------------------------------------------------------- @Test public void testStopWatchSimple() { final StopWatch watch = StopWatch.createStarted(); @@ -238,7 +276,7 @@ public void testStopWatchSimple() { public void testStopWatchSimpleGet() { final StopWatch watch = new StopWatch(); assertEquals(0, watch.getTime()); - assertEquals("00:00:00.000", watch.toString()); + assertEquals(ZERO_TIME_ELAPSED, watch.toString()); watch.start(); try { @@ -329,4 +367,48 @@ public void testToSplitString() { final String splitStr = watch.toSplitString(); assertEquals(splitStr.length(), 12, "Formatted split string not the correct length"); } + + @Test + public void testToSplitStringWithMessage() { + final StopWatch watch = new StopWatch(MESSAGE); + watch.start(); + try { + Thread.sleep(550); + } catch (final InterruptedException ex) { + // ignore + } + watch.split(); + final String splitStr = watch.toSplitString(); + assertEquals(splitStr.length(), 12 + MESSAGE.length() + 1, "Formatted split string not the correct length"); + } + + @Test + public void testToString() { + // + final StopWatch watch = StopWatch.createStarted(); + try { + Thread.sleep(550); + } catch (final InterruptedException ex) { + // ignore + } + watch.split(); + final String splitStr = watch.toString(); + assertEquals(splitStr.length(), 12, "Formatted split string not the correct length"); + } + + @Test + public void testToStringWithMessage() { + assertTrue(new StopWatch(MESSAGE).toString().startsWith(MESSAGE)); + // + final StopWatch watch = new StopWatch(MESSAGE); + watch.start(); + try { + Thread.sleep(550); + } catch (final InterruptedException ex) { + // ignore + } + watch.split(); + final String splitStr = watch.toString(); + assertEquals(splitStr.length(), 12 + MESSAGE.length() + 1, "Formatted split string not the correct length"); + } }