diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/diagnostics/TraceDiagnostic.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/diagnostics/TraceDiagnostic.java index 60ebb1c94..c8b53a44f 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/diagnostics/TraceDiagnostic.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/diagnostics/TraceDiagnostic.java @@ -15,6 +15,7 @@ */ package io.github.ascopes.jct.diagnostics; +import static java.util.Collections.unmodifiableList; import static java.util.Objects.requireNonNull; import io.github.ascopes.jct.annotations.Nullable; @@ -65,7 +66,7 @@ public TraceDiagnostic( this.timestamp = requireNonNull(timestamp, "timestamp"); this.threadId = threadId; this.threadName = threadName; - this.stackTrace = requireNonNull(stackTrace, "stackTrace"); + this.stackTrace = unmodifiableList(requireNonNull(stackTrace, "stackTrace")); this.original = requireNonNull(original, "original"); } @@ -137,7 +138,7 @@ public long getThreadId() { /** * Get the thread name for the thread that created this diagnostic. * - * @return the thread name, if known. + * @return the thread name, if known, or an empty optional otherwise. */ public Optional getThreadName() { return Optional.ofNullable(threadName); @@ -146,7 +147,7 @@ public Optional getThreadName() { /** * Get the stacktrace of where the diagnostic was written from. * - * @return the stacktrace. + * @return the stacktrace, in an unmodifiable list. */ public List getStackTrace() { return stackTrace; @@ -158,11 +159,11 @@ public String toString() { .attribute("timestamp", timestamp) .attribute("threadId", threadId) .attribute("threadName", threadName) - .attribute("kind", getKind()) - .attribute("code", getCode()) - .attribute("column", getColumnNumber()) - .attribute("line", getLineNumber()) - .attribute("message", getMessage(Locale.ROOT)) + .attribute("kind", original.getKind()) + .attribute("code", original.getCode()) + .attribute("column", original.getColumnNumber()) + .attribute("line", original.getLineNumber()) + .attribute("message", original.getMessage(Locale.ROOT)) .toString(); } } diff --git a/java-compiler-testing/src/test/java/io/github/ascopes/jct/testing/unit/diagnostics/TraceDiagnosticTest.java b/java-compiler-testing/src/test/java/io/github/ascopes/jct/testing/unit/diagnostics/TraceDiagnosticTest.java index 3669664ef..09f85eb3c 100644 --- a/java-compiler-testing/src/test/java/io/github/ascopes/jct/testing/unit/diagnostics/TraceDiagnosticTest.java +++ b/java-compiler-testing/src/test/java/io/github/ascopes/jct/testing/unit/diagnostics/TraceDiagnosticTest.java @@ -19,12 +19,11 @@ import static io.github.ascopes.jct.testing.helpers.Fixtures.someStackTraceList; import static java.time.Instant.now; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.BDDAssertions.then; -import static org.assertj.core.api.BDDAssertions.thenCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.verify; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import io.github.ascopes.jct.diagnostics.TraceDiagnostic; import java.util.Locale; @@ -50,8 +49,11 @@ class TraceDiagnosticTest { @DisplayName("null original diagnostics are rejected") @Test void nullDiagnosticsAreRejected() { + // Given var stack = someStackTraceList(); - thenCode(() -> new TraceDiagnostic<>(now(), 123, "foo", stack, null)) + + // Then + assertThatThrownBy(() -> new TraceDiagnostic<>(now(), 123, "foo", stack, null)) .isInstanceOf(NullPointerException.class) .hasMessage("original"); } @@ -64,7 +66,7 @@ void getKindDelegates(Kind expected) { var original = someDiagnostic(); var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); - given(original.getKind()).willReturn(expected); + when(original.getKind()).thenReturn(expected); // Then assertThat(wrapped.getKind()).isSameAs(expected); @@ -78,8 +80,7 @@ void getSourceDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var source = mock(JavaFileObject.class); - - given(original.getSource()).willReturn(source); + when(original.getSource()).thenReturn(source); // Then assertThat(wrapped.getSource()).isSameAs(source); @@ -93,7 +94,7 @@ void getPositionDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var position = new Random().nextLong(); - given(original.getPosition()).willReturn(position); + when(original.getPosition()).thenReturn(position); // Then assertThat(wrapped.getPosition()).isEqualTo(position); @@ -107,7 +108,7 @@ void getStartPositionDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var startPosition = new Random().nextLong(); - given(original.getStartPosition()).willReturn(startPosition); + when(original.getStartPosition()).thenReturn(startPosition); // Then assertThat(wrapped.getStartPosition()).isEqualTo(startPosition); @@ -121,7 +122,7 @@ void getEndPositionDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var endPosition = new Random().nextLong(); - given(original.getEndPosition()).willReturn(endPosition); + when(original.getEndPosition()).thenReturn(endPosition); // Then assertThat(wrapped.getEndPosition()).isEqualTo(endPosition); @@ -135,7 +136,7 @@ void getLineNumberDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var lineNumber = new Random().nextLong(); - given(original.getLineNumber()).willReturn(lineNumber); + when(original.getLineNumber()).thenReturn(lineNumber); // Then assertThat(wrapped.getLineNumber()).isEqualTo(lineNumber); @@ -149,7 +150,7 @@ void getColumnNumberDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var columnNumber = new Random().nextLong(); - given(original.getColumnNumber()).willReturn(columnNumber); + when(original.getColumnNumber()).thenReturn(columnNumber); // Then assertThat(wrapped.getColumnNumber()).isEqualTo(columnNumber); @@ -164,7 +165,7 @@ void getCodeDelegates(String expected) { var original = someDiagnostic(); var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); - given(original.getCode()).willReturn(expected); + when(original.getCode()).thenReturn(expected); // Then assertThat(wrapped.getCode()).isSameAs(expected); @@ -178,7 +179,7 @@ void getMessageDelegates() { var stack = someStackTraceList(); var wrapped = new TraceDiagnostic<>(now(), 123, "foo", stack, original); var message = UUID.randomUUID().toString(); - given(original.getMessage(any())).willReturn(message); + when(original.getMessage(any())).thenReturn(message); // Then assertThat(wrapped.getMessage(Locale.TAIWAN)).isSameAs(message); @@ -190,7 +191,7 @@ void getMessageDelegates() { void nullTimestampsAreRejected() { var diag = someDiagnostic(); var stack = someStackTraceList(); - thenCode(() -> new TraceDiagnostic<>(null, 123, "foo", stack, diag)) + assertThatThrownBy(() -> new TraceDiagnostic<>(null, 123, "foo", stack, diag)) .isInstanceOf(NullPointerException.class) .hasMessage("timestamp"); } @@ -200,7 +201,7 @@ void nullTimestampsAreRejected() { void nullStackTracesAreRejected() { var now = now(); var diag = someDiagnostic(); - thenCode(() -> new TraceDiagnostic<>(now, 123, "foo", null, diag)) + assertThatThrownBy(() -> new TraceDiagnostic<>(now, 123, "foo", null, diag)) .isInstanceOf(NullPointerException.class) .hasMessage("stackTrace"); } @@ -222,7 +223,7 @@ void getTimestampReturnsTheTimestamp() { var actualTimestamp = diagnostic.getTimestamp(); // Then - then(actualTimestamp).isEqualTo(expectedTimestamp); + assertThat(actualTimestamp).isEqualTo(expectedTimestamp); } @DisplayName("getThreadId() returns the thread ID") @@ -242,7 +243,7 @@ void getThreadIdReturnsTheThreadId() { var actualThreadId = diagnostic.getThreadId(); // Then - then(actualThreadId).isEqualTo(expectedThreadId); + assertThat(actualThreadId).isEqualTo(expectedThreadId); } @DisplayName("getThreadName() returns the thread name when known") @@ -262,7 +263,7 @@ void getThreadNameReturnsTheThreadNameWhenKnown() { var actualThreadName = diagnostic.getThreadName(); // Then - then(actualThreadName).isPresent().contains(expectedThreadName); + assertThat(actualThreadName).isPresent().contains(expectedThreadName); } @DisplayName("getThreadName() returns empty when the thread name is not known") @@ -281,7 +282,7 @@ void getThreadNameReturnsEmptyWhenTheThreadNameIsNotKnown() { var actualThreadName = diagnostic.getThreadName(); // Then - then(actualThreadName).isEmpty(); + assertThat(actualThreadName).isEmpty(); } @DisplayName("getStackTrace() returns the stack trace") @@ -301,6 +302,26 @@ void getStackTraceReturnsTheStackTrace() { var actualStackTrace = diagnostic.getStackTrace(); // Then - then(actualStackTrace).isSameAs(expectedStackTrace); + assertThat(actualStackTrace).isEqualTo(expectedStackTrace); + } + + @DisplayName("getStackTrace() returns an immutable list") + @Test + void getStackTraceReturnsAnImmutableStackTrace() { + // Given + var expectedStackTrace = someStackTraceList(); + var diagnostic = new TraceDiagnostic<>( + now(), + 1234, + "foo", + expectedStackTrace, + someDiagnostic() + ); + + var actualStackTrace = diagnostic.getStackTrace(); + + // Then + assertThatThrownBy(() -> actualStackTrace.remove(0)) + .isInstanceOf(UnsupportedOperationException.class); } }