Skip to content

Commit c37ddfa

Browse files
committed
La till Docstrings efter feedback.
1 parent e323a3c commit c37ddfa

9 files changed

Lines changed: 98 additions & 6 deletions

File tree

src/main/java/com/example/FxUtils.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
public class FxUtils {
66

7+
/**
8+
* Runs a task on the JavaFX thread.
9+
* If already on the thread, runs immediately.
10+
* If not, schedules it to run later.
11+
* If JavaFX is not initialized, runs on the current thread.
12+
*/
13+
714
public static void runOnFx(Runnable task) {
815
try {
916
if (Platform.isFxApplicationThread()) {

src/main/java/com/example/HelloController.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
import java.time.format.DateTimeFormatter;
1414

1515
/**
16-
* Controller layer: mediates between the view (FXML) and the model.
16+
* Controller for the chat app.
17+
* <p>
18+
* Connects the FXML view to the HelloModel.
19+
* Handles sending messages, changing topics, and updating the UI.
1720
*/
1821

1922
public class HelloController {

src/main/java/com/example/HelloFX.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
import java.util.Objects;
1010

11+
/**
12+
* Main JavaFX application class for RuneChat.
13+
* <p>
14+
* Loads the FXML view, applies the stylesheet, and starts the application window.
15+
*/
16+
1117
public class HelloFX extends Application {
1218

1319
@Override

src/main/java/com/example/HelloModel.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
import static com.example.FxUtils.runOnFx;
1212

13+
/**
14+
* Model layer for the chatapp RuneChat.
15+
* <p>
16+
* Manages messages, the current topic, and sending/receiving messages via NtfyConnection.
17+
*/
18+
1319
public class HelloModel {
1420

1521
private final NtfyConnection connection;

src/main/java/com/example/NtfyConnection.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,30 @@
44
import java.util.concurrent.TimeUnit;
55
import java.util.function.Consumer;
66

7+
/**
8+
* Interface for sending and receiving messages via a notification service.
9+
*/
710
public interface NtfyConnection {
811

912
void send(String message, Consumer<Boolean> callback);
1013

14+
/**
15+
* Receives messages from the service.
16+
* @param messageHandler called for each received message
17+
*/
1118
void receive(Consumer<NtfyMessageDto> messageHandler);
1219

20+
/** Returns the current topic. Default is "mytopic". */
1321
default String getCurrentTopic() {
1422
return "mytopic";
1523
}
1624

25+
/** Sets the current topic. Default does nothing. */
1726
default void setCurrentTopic(String topic) {
1827

1928
}
2029

30+
/** Returns the user ID. Default is "unknown". */
2131
default String getUserId() {
2232
return "unknown";
2333
}

src/main/java/com/example/NtfyConnectionImpl.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import java.util.Objects;
1111
import java.util.function.Consumer;
1212

13+
/**
14+
* Implementation of NtfyConnection using HTTP for sending and receiving messages.
15+
*/
1316
public class NtfyConnectionImpl implements NtfyConnection {
1417

1518
private final HttpClient http = HttpClient.newHttpClient();
@@ -18,37 +21,48 @@ public class NtfyConnectionImpl implements NtfyConnection {
1821
private String currentTopic;
1922
private final ObjectMapper mapper = new ObjectMapper();
2023

24+
/** Loads configuration from environment variables. */
2125
public NtfyConnectionImpl() {
2226
Dotenv dotenv = Dotenv.load();
2327
this.hostName = Objects.requireNonNull(dotenv.get("HOST_NAME"));
2428
this.userId = Objects.requireNonNull(dotenv.get("USER_ID"), "USER_ID");
2529
this.currentTopic = dotenv.get("DEFAULT_TOPIC", "mytopic");
2630
}
2731

32+
/** Creates connection with a custom host, default user and topic. */
2833
public NtfyConnectionImpl(String hostName) {
2934
this.hostName = hostName;
3035
this.userId = "testuser";
3136
this.currentTopic = "mytopic";
3237
}
3338

39+
/** Creates connection with custom host, user, and topic. */
3440
public NtfyConnectionImpl(String hostName, String userId, String topic) {
3541
this.hostName = hostName;
3642
this.userId = userId;
3743
this.currentTopic = topic;
3844
}
3945

46+
/** Returns the user ID. */
4047
public String getUserId() {
4148
return userId;
4249
}
4350

51+
/** Returns the current topic. */
4452
public String getCurrentTopic() {
4553
return currentTopic;
4654
}
4755

56+
/** Sets the current topic. */
4857
public void setCurrentTopic(String topic) {
4958
this.currentTopic = topic;
5059
}
5160

61+
/**
62+
* Sends a message asynchronously to the current topic.
63+
* @param message message to send
64+
* @param callback called with true if successful, false otherwise
65+
*/
5266
@Override
5367
public void send(String message, Consumer<Boolean> callback) {
5468
HttpRequest httpRequest = HttpRequest.newBuilder()
@@ -67,6 +81,10 @@ public void send(String message, Consumer<Boolean> callback) {
6781
.thenAccept(callback);
6882
}
6983

84+
/**
85+
* Receives messages from the current topic asynchronously.
86+
* @param messageHandler called for each received message
87+
*/
7088
@Override
7189
public void receive(Consumer<NtfyMessageDto> messageHandler) {
7290
HttpRequest httpRequest = HttpRequest.newBuilder()

src/main/java/com/example/NtfyMessageDto.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44

5+
/**
6+
* Data transfer object for messages from the Ntfy server.
7+
*/
58
@JsonIgnoreProperties(ignoreUnknown = true)
69
public record NtfyMessageDto(String id, long time, String event, String topic, String message) {
710
}

src/test/java/com/example/HelloModelTest.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ static void initToolkit() {
2323
}
2424

2525

26+
/**
27+
* Verifies that a valid message is sent successfully and captured by the connection spy.
28+
*/
2629
@Test
27-
@DisplayName("Should send message successfully when message is valid")
30+
@DisplayName("Should send message successfully when message is valid.")
2831
void shouldSendValidMessageSuccessfully() throws InterruptedException {
2932
// Arrange
3033
var spy = new NtfyConnectionSpy();
@@ -43,8 +46,11 @@ void shouldSendValidMessageSuccessfully() throws InterruptedException {
4346
assertThat(spy.message).isEqualTo("Hello World");
4447
}
4548

49+
/**
50+
* Ensures the message input field is cleared after a successful send operation.
51+
*/
4652
@Test
47-
@DisplayName("Should clear message field after successful send")
53+
@DisplayName("Should clear message field after successful send.")
4854
void shouldClearMessageFieldAfterSuccessfulSend() throws InterruptedException {
4955
// Arrange
5056
var spy = new NtfyConnectionSpy();
@@ -63,6 +69,9 @@ void shouldClearMessageFieldAfterSuccessfulSend() throws InterruptedException {
6369
assertThat(model.getMessageToSend()).isEmpty();
6470
}
6571

72+
/**
73+
* Confirms that sending an empty string returns false and does not trigger a send.
74+
*/
6675
@Test
6776
@DisplayName("Should return false when sending empty string")
6877
void shouldReturnFalseForEmptyMessage() throws InterruptedException {
@@ -88,6 +97,9 @@ void shouldReturnFalseForEmptyMessage() throws InterruptedException {
8897
assertThat(spy.message).isNull();
8998
}
9099

100+
/**
101+
* Confirms that sending a null message returns false and does not trigger a send.
102+
*/
91103
@Test
92104
@DisplayName("Should return false when sending null message")
93105
void shouldReturnFalseForNullMessage() throws InterruptedException {
@@ -113,6 +125,9 @@ void shouldReturnFalseForNullMessage() throws InterruptedException {
113125
assertThat(spy.message).isNull();
114126
}
115127

128+
/**
129+
* Ensures failed sends are handled gracefully: callback receives false, message is retained.
130+
*/
116131
@Test
117132
@DisplayName("Should handle failed send and keep message")
118133
void shouldHandleFailedSendGracefully() throws InterruptedException {
@@ -145,6 +160,9 @@ public void receive(Consumer<NtfyMessageDto> messageHandler) { }
145160
assertThat(model.getMessageToSend()).isEqualTo("Fail this message");
146161
}
147162

163+
/**
164+
* Verifies multiple sequential sends are processed correctly in order.
165+
*/
148166
@Test
149167
@DisplayName("Should handle multiple sequential sends correctly")
150168
void shouldHandleMultipleSequentialSends() throws InterruptedException {
@@ -177,6 +195,9 @@ void shouldHandleMultipleSequentialSends() throws InterruptedException {
177195
assertThat(spy.message).isEqualTo("Second");
178196
}
179197

198+
/**
199+
* Ensures exceptions during send are caught and result in a failed callback (false).
200+
*/
180201
@Test
181202
@DisplayName("Should handle exceptions during send gracefully")
182203
void shouldHandleExceptionsDuringSend() throws InterruptedException {
@@ -219,8 +240,9 @@ public void receive(Consumer<NtfyMessageDto> messageHandler) { }
219240
}
220241
}
221242

222-
// ========== RECEIVE MESSAGE TESTS ==========
223-
243+
/**
244+
* Verifies that a valid incoming message is added to the observable message list.
245+
*/
224246
@Test
225247
@DisplayName("Should add received message to message list")
226248
void shouldAddReceivedMessageToList() throws InterruptedException {
@@ -249,6 +271,9 @@ void shouldAddReceivedMessageToList() throws InterruptedException {
249271
assertThat(model.getMessages()).contains(message);
250272
}
251273

274+
/**
275+
* Ensures null messages received from the connection are ignored and not added.
276+
*/
252277
@Test
253278
@DisplayName("Should ignore null received messages")
254279
void shouldIgnoreNullReceivedMessages() throws InterruptedException {
@@ -273,6 +298,9 @@ void shouldIgnoreNullReceivedMessages() throws InterruptedException {
273298
assertThat(model.getMessages()).isEmpty();
274299
}
275300

301+
/**
302+
* Confirms messages with blank or empty content are filtered out and not added.
303+
*/
276304
@Test
277305
@DisplayName("Should ignore messages with blank or empty content")
278306
void shouldIgnoreBlankOrEmptyMessages() throws InterruptedException {
@@ -301,6 +329,9 @@ void shouldIgnoreBlankOrEmptyMessages() throws InterruptedException {
301329
assertThat(model.getMessages()).isEmpty();
302330
}
303331

332+
/**
333+
* Verifies multiple incoming messages are added in the correct arrival order.
334+
*/
304335
@Test
305336
@DisplayName("Should add multiple received messages in correct order")
306337
void shouldAddMultipleMessagesInOrder() throws InterruptedException {
@@ -337,8 +368,10 @@ void shouldAddMultipleMessagesInOrder() throws InterruptedException {
337368
assertThat(model.getMessages().get(2)).isEqualTo(message3);
338369
}
339370

340-
// ========== INTEGRATION TESTS ==========
341371

372+
/**
373+
* Integration test: verifies message is successfully sent to a mocked Ntfy server via HTTP.
374+
*/
342375
@Test
343376
@DisplayName("Should send message to fake server successfully")
344377
void shouldSendMessageToFakeServer(WireMockRuntimeInfo wmRuntimeInfo) throws InterruptedException {

src/test/java/com/example/NtfyConnectionSpy.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
22

33
import java.util.function.Consumer;
44

5+
/**
6+
* Spy for testing NtfyConnection: captures sent messages and simulates incoming ones.
7+
*/
58
public class NtfyConnectionSpy implements NtfyConnection{
69

710
String message;
811
Consumer<NtfyMessageDto> handler;
912

13+
/** Captures message and calls callback with true on a background thread. */
1014
@Override
1115
public void send(String message, Consumer<Boolean> callback) {
1216
this.message = message;
1317
new Thread(() -> callback.accept(true)).start();
1418
}
1519

1620

21+
/** Saves the handler for incoming messages. */
1722
@Override
1823
public void receive(Consumer<NtfyMessageDto> messageHandler) {
1924
this.handler = messageHandler;
2025
}
2126

27+
/** Triggers the saved handler with the given message, if there is any. */
2228
public void simulateIncoming(NtfyMessageDto msg) {
2329
if (handler != null) handler.accept(msg);
2430
}

0 commit comments

Comments
 (0)