Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ sourceSets{
kotlin{
srcDirs("test")
}
java{
srcDirs("test")
}
}
}

Expand Down
11 changes: 7 additions & 4 deletions app/src/processing/app/UpdateCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,15 @@ protected boolean promptToOpenContributionManager() {
*/


protected int readInt(String filename) throws IOException {
protected static int readInt(String filename) throws IOException {
URL url = new URL(filename);
InputStream stream = url.openStream();

// try-with-resources auto closes things of type "Closeable" even the code throws an error
try(InputStream stream = url.openStream();
InputStreamReader isr = new InputStreamReader(stream);
BufferedReader reader = new BufferedReader(isr);
return Integer.parseInt(reader.readLine());
BufferedReader reader = new BufferedReader(isr)) {
return Integer.parseInt(reader.readLine().trim());
}
Comment on lines +211 to +215
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really cool! good use of try-with-resources.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added tests to the UpdateCheckTest.java file, with 16 tests. Also, Mark and I noticed that in the build.gradle.kts file under the app build, only kotlin tests are ran. So, I modified that file to include java tests.

}


Expand Down
153 changes: 153 additions & 0 deletions app/test/processing/app/UpdateCheckTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package processing.app;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class UpdateCheckTest {

@TempDir
Path tempDir;

// Helper: write content to a temp file and return its URL string
private String createTempFile(String content) throws IOException {
Path file = tempDir.resolve("test.txt");
Files.writeString(file, content, StandardCharsets.UTF_8);
return file.toUri().toString();
}


// tests to show that the method returns what it should
@Test
void readInt_simpleInteger_returnsCorrectValue() throws IOException {
String url = createTempFile("42\n");
assertEquals(42, UpdateCheck.readInt(url));
}

@Test
void readInt_negativeInteger_returnsCorrectValue() throws IOException {
String url = createTempFile("-7\n");
assertEquals(-7, UpdateCheck.readInt(url));
}

@Test
void readInt_integerWithLeadingAndTrailingWhitespace_returnsCorrectValue() throws IOException {
String url = createTempFile(" 100 \n");
assertEquals(100, UpdateCheck.readInt(url));
}

@Test
void readInt_integerWithNoNewline_returnsCorrectValue() throws IOException {
String url = createTempFile("99");
assertEquals(99, UpdateCheck.readInt(url));
}

@Test
void readInt_maxInt_returnsCorrectValue() throws IOException {
String url = createTempFile(String.valueOf(Integer.MAX_VALUE));
assertEquals(Integer.MAX_VALUE, UpdateCheck.readInt(url));
}

@Test
void readInt_minInt_returnsCorrectValue() throws IOException {
String url = createTempFile(String.valueOf(Integer.MIN_VALUE));
assertEquals(Integer.MIN_VALUE, UpdateCheck.readInt(url));
}

@Test
void readInt_integerWithMultipleLines_readsOnlyFirstLine() throws IOException {
String url = createTempFile("5\n10\n15");
assertEquals(5, UpdateCheck.readInt(url));
}

// checks for if errors are correctly reported
@Test
void readInt_nonNumericContent_throwsNumberFormatException() throws IOException {
String url = createTempFile("not-a-number\n");
assertThrows(NumberFormatException.class, () -> UpdateCheck.readInt(url));
}

@Test
void readInt_emptyFile_throwsNullPointerException() throws IOException {
String url = createTempFile("");
// readLine() returns null on empty stream → trim() throws NPE
assertThrows(Exception.class, () -> UpdateCheck.readInt(url));
}

@Test
void readInt_blankLine_throwsNumberFormatException() throws IOException {
String url = createTempFile(" \n");
assertThrows(NumberFormatException.class, () -> UpdateCheck.readInt(url));
}

@Test
void readInt_floatValue_throwsNumberFormatException() throws IOException {
String url = createTempFile("3.14\n");
assertThrows(NumberFormatException.class, () -> UpdateCheck.readInt(url));
}

@Test
void readInt_overflowValue_throwsNumberFormatException() throws IOException {
String url = createTempFile("99999999999999\n");
assertThrows(NumberFormatException.class, () -> UpdateCheck.readInt(url));
}

@Test
void readInt_invalidUrl_throwsMalformedURLException() {
assertThrows(MalformedURLException.class,
() -> UpdateCheck.readInt("not-a-valid-url"));
}

@Test
void readInt_nonExistentFile_throwsIOException() {
String nonExistent = tempDir.resolve("ghost.txt").toUri().toString();
assertThrows(IOException.class, () -> UpdateCheck.readInt(nonExistent));
}

// checks for if streams are closed
@Test
void readInt_streamIsClosedAfterSuccessfulRead() throws IOException {
// Spy on the InputStream to verify close() is called
Path file = tempDir.resolve("close_test.txt");
Files.writeString(file, "7", StandardCharsets.UTF_8);

URL url = file.toUri().toURL();
InputStream realStream = url.openStream();
InputStream spyStream = spy(realStream);

try (MockedConstruction<URL> mockedUrl = mockConstruction(URL.class,
(mock, ctx) -> when(mock.openStream()).thenReturn(spyStream))) {

UpdateCheck.readInt(file.toUri().toString());
}

verify(spyStream, atLeastOnce()).close();
}

@Test
void readInt_streamIsClosedEvenWhenParseThrows() throws IOException {
Path file = tempDir.resolve("bad_close_test.txt");
Files.writeString(file, "not-a-number", StandardCharsets.UTF_8);

URL url = file.toUri().toURL();
InputStream realStream = url.openStream();
InputStream spyStream = spy(realStream);

try (MockedConstruction<URL> mockedUrl = mockConstruction(URL.class,
(mock, ctx) -> when(mock.openStream()).thenReturn(spyStream))) {

assertThrows(NumberFormatException.class,
() -> UpdateCheck.readInt(file.toUri().toString()));
}

verify(spyStream, atLeastOnce()).close();
}
}