From 5cfd9032c64464b2926c575105ade34c23b694a9 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 25 Oct 2022 16:42:46 +0200 Subject: [PATCH 1/4] Delete left-over dummy test This test was necessary because otherwise the unit tests would fail due to a lack of unit tests in this file --- .../test/net/sf/openrocket/communication/UpdateInfoTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/test/net/sf/openrocket/communication/UpdateInfoTest.java b/core/test/net/sf/openrocket/communication/UpdateInfoTest.java index 5b2f18daa..025d00190 100644 --- a/core/test/net/sf/openrocket/communication/UpdateInfoTest.java +++ b/core/test/net/sf/openrocket/communication/UpdateInfoTest.java @@ -26,11 +26,6 @@ public class UpdateInfoTest extends BaseTestCase { /** How much long does the test allow it to take */ private static final int ALLOWANCE = 2000; - @Test - public void dummyTest() { - // Yes, I passed! - } - // TODO: write unit test for new software update /*private HttpURLConnectionMock setup() { HttpURLConnectionMock connection = new HttpURLConnectionMock(); From 99913b69842c9056e9d2eb43d83e8c73b250310b Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 26 Oct 2022 11:39:47 +0200 Subject: [PATCH 2/4] Improve software updater compareLatest --- .../communication/UpdateInfoRetriever.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java index 4018c12b6..8edd7c481 100644 --- a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java +++ b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java @@ -403,6 +403,10 @@ public class UpdateInfoRetriever { String[] tag1Split = tag1.split("[.-]"); String[] tag2Split = tag2.split("[.-]"); + // Check malformed tags + checkMalformedReleaseTag(tag1Split); + checkMalformedReleaseTag(tag2Split); + for (int i = 0; i < tag2Split.length; i++) { // If the loop is still going until this condition, you have the situation where tag1 is e.g. // '15.03' and tag2 '15.03.01', so tag is in that case the more recent version. @@ -437,7 +441,7 @@ public class UpdateInfoRetriever { // In case tag1 is e.g. '20.alpha.01', but tag2 is already an official release with a number instead of // a text, e.g. '20.01' if (tag2Split[i].matches("\\d+")) { - return ReleaseStatus.NEWER; + return ReleaseStatus.OLDER; } String message = String.format("Unrecognized release tag format, tag 1: %s, tag 2: %s", tag1, tag2); @@ -449,12 +453,45 @@ public class UpdateInfoRetriever { // If tag 1 is bigger than tag 2 and by this point, all the other elements of the tags were the same, tag 1 // must be newer (e.g. tag 1 = '15.03.01' and tag 2 = '15.03'). if (tag1Split.length > tag2Split.length) { + // If tag 1 is e.g. 22.02.beta.01, and tag 2 22.02, then tag 1 is older (tag 2 is an official release of 22.02) + if (devTags.containsKey(tag1Split[tag2Split.length])) { + return ReleaseStatus.OLDER; + } return ReleaseStatus.NEWER; } return ReleaseStatus.LATEST; } + private static void checkMalformedReleaseTag(String[] tagSplit) throws UpdateCheckerException { + if (tagSplit.length == 0) { + String message = "Zero-length tag"; + log.warn(message); + throw new UpdateCheckerException(message); + } + for (int i = 0; i < tagSplit.length; i++) { + try { + int test = Integer.parseInt(tagSplit[i]); + if (test < 0) { + String message = String.format("Tag item must be greater than zero, tag: '%s'", String.join(".", tagSplit)); + log.warn(message); + throw new UpdateCheckerException(message); + } + } catch (NumberFormatException e) { + if (i == 0) { + String message = String.format("First tag item must be decimal, tag: '%s'", String.join(".", tagSplit)); + log.warn(message); + throw new UpdateCheckerException(message); + } + if (!devTags.containsKey(tagSplit[i])) { + String message = String.format("Malformed release tag: '%s'", String.join(".", tagSplit)); + log.warn(message); + throw new UpdateCheckerException(message); + } + } + } + } + /** * Generate a URL with a set of parameters included. * E.g. url = github.com/openrocket/openrocket/releases, params = {"lorem", "ipsum"} From cf860b3916f55454728c451ad6d7424630982ace Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 27 Oct 2022 15:38:59 +0200 Subject: [PATCH 3/4] Improve software updater --- .../openrocket/communication/ReleaseInfo.java | 19 ++++++++++--------- .../communication/UpdateInfoRetriever.java | 12 +++++++----- .../gui/dialogs/UpdateInfoDialog.java | 2 -- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/core/src/net/sf/openrocket/communication/ReleaseInfo.java b/core/src/net/sf/openrocket/communication/ReleaseInfo.java index 8d4134a8c..9f9233512 100644 --- a/core/src/net/sf/openrocket/communication/ReleaseInfo.java +++ b/core/src/net/sf/openrocket/communication/ReleaseInfo.java @@ -1,5 +1,6 @@ package net.sf.openrocket.communication; +import com.sun.istack.NotNull; import net.sf.openrocket.util.ArrayList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -7,6 +8,7 @@ import org.slf4j.LoggerFactory; import javax.json.JsonArray; import javax.json.JsonObject; import java.util.List; +import java.util.Objects; /** * Class containing info about a GitHub release. All the info is stored in a JSON objects, retrieved using the GitHub @@ -21,8 +23,8 @@ public class ReleaseInfo { private static final Logger log = LoggerFactory.getLogger(ReleaseInfo.class); - public ReleaseInfo(JsonObject obj) { - this.obj = obj; + public ReleaseInfo(@NotNull JsonObject obj) { + this.obj = Objects.requireNonNull(obj, "JsonObject cannot be null"); } /** @@ -30,8 +32,6 @@ public class ReleaseInfo { * @return release name (e.g. "15.0.3") */ public String getReleaseName() { - if (this.obj == null) return null; - String name = this.obj.get("tag_name").toString(); // Release label is encapsulated in the 'tag_name'-tag name = name.replaceAll("^\"+|\"+$", ""); // Remove double quotations in the beginning and end @@ -50,8 +50,9 @@ public class ReleaseInfo { * @return release notes (this is the text that explains a certain GitHub release) */ public String getReleaseNotes() { - if (this.obj == null) return null; - return this.obj.get("body").toString(); + String releaseNotes = this.obj.get("body").toString(); + releaseNotes = releaseNotes.replaceAll("^\"+|\"+$", ""); // Remove double quotations in the beginning and end + return releaseNotes; } /** @@ -59,8 +60,9 @@ public class ReleaseInfo { * @return release URL (e.g. 'https://github.com/openrocket/openrocket/releases/tag/release-15.03') */ public String getReleaseURL() { - if (this.obj == null) return null; - return this.obj.get("html_url").toString(); + String releaseURL = this.obj.get("html_url").toString(); + releaseURL = releaseURL.replaceAll("^\"+|\"+$", ""); // Remove double quotations in the beginning and end + return releaseURL; } /** @@ -68,7 +70,6 @@ public class ReleaseInfo { * @return list of asset download URLs (e.g. 'https://github.com/openrocket/openrocket/releases/download/release-15.03/OpenRocket-15.03-installer.exe') */ public List getAssetURLs() { - if (this.obj == null) return null; List assetURLs = new ArrayList<>(); JsonArray assets = this.obj.getJsonArray("assets"); diff --git a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java index 8edd7c481..692df1834 100644 --- a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java +++ b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java @@ -282,10 +282,12 @@ public class UpdateInfoRetriever { * This function extracts all the release names that start with the specified preTag. * If preTag is null, the default release names without a pre-tag, starting with a number, are returned (e.g. '15.03'). * @param names list of release names to filter - * @param preTag pre-tag to filter the names on. If null, no special preTag filtering is applied + * @param preTag pre-tag to filter the names on. If null, return all tags that start with a number * @return list of names starting with the preTag */ - public List filterReleasePreTag(List names, String preTag) { + public static List filterReleasePreTag(List names, String preTag) { + if (names == null) return null; + List filteredTags = new LinkedList<>(); // Filter out the names that are not related to the preTag @@ -317,7 +319,7 @@ public class UpdateInfoRetriever { * @param tags filter tags * @return list of release names containing the filter tag */ - public List filterReleaseTags(List names, String[] tags) { + public static List filterReleaseTags(List names, String[] tags) { if (names == null) return null; if (tags == null) return names; return names.stream().filter(c -> Arrays.stream(tags) @@ -330,7 +332,7 @@ public class UpdateInfoRetriever { * @param names list of release names to filter * @return list of release names that do not contain a devTag */ - public List filterOfficialRelease(List names) { + public static List filterOfficialRelease(List names) { if (names == null) return null; return names.stream().filter(c -> Arrays.stream(devTags.keySet().toArray(new String[0])) .noneMatch(c::contains)).collect(Collectors.toList()); @@ -346,7 +348,7 @@ public class UpdateInfoRetriever { * @param onlyOfficial bool to check whether to only include official (non-test) releases * @return latest JSON GitHub release object */ - public JsonObject getLatestReleaseJSON(JsonArray jsonArr, String preTag, String[] tags, boolean onlyOfficial) throws UpdateCheckerException { + public static JsonObject getLatestReleaseJSON(JsonArray jsonArr, String preTag, String[] tags, boolean onlyOfficial) throws UpdateCheckerException { if (jsonArr == null) return null; JsonObject latestObj = null; diff --git a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java index 3a8cc9bcf..e00f96152 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java @@ -84,12 +84,10 @@ public class UpdateInfoDialog extends JDialog { // Release notes String releaseNotes = release.getReleaseNotes(); - releaseNotes = releaseNotes.replaceAll("^\"|\"$", ""); // Remove leading and trailing quotations sb.append(MarkdownUtil.toHtml(releaseNotes)).append("

"); // GitHub link String releaseURL = release.getReleaseURL(); - releaseURL = releaseURL.replaceAll("^\"|\"$", ""); // Remove leading and trailing quotations sb.append(String.format("%s", releaseURL, trans.get("update.dlg.updateAvailable.txtPane.readMore"))); sb.append(""); textPane.addHyperlinkListener(new HyperlinkListener() { From 70eb5ea33f727811f28c75d112cdc02373e20e50 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 27 Oct 2022 15:39:10 +0200 Subject: [PATCH 4/4] Add unit tests for software updater --- .../communication/UpdateInfoTest.java | 414 +++++++++++++++--- 1 file changed, 356 insertions(+), 58 deletions(-) diff --git a/core/test/net/sf/openrocket/communication/UpdateInfoTest.java b/core/test/net/sf/openrocket/communication/UpdateInfoTest.java index 025d00190..3f13cfb52 100644 --- a/core/test/net/sf/openrocket/communication/UpdateInfoTest.java +++ b/core/test/net/sf/openrocket/communication/UpdateInfoTest.java @@ -1,23 +1,23 @@ package net.sf.openrocket.communication; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.IOException; -import java.util.Collections; +import java.util.Arrays; import java.util.List; -import java.util.Random; -import net.sf.openrocket.util.BuildProperties; -import net.sf.openrocket.util.ComparablePair; import net.sf.openrocket.util.BaseTestCase.BaseTestCase; import org.junit.Test; +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; + public class UpdateInfoTest extends BaseTestCase { /** The connection delay */ @@ -26,17 +26,315 @@ public class UpdateInfoTest extends BaseTestCase { /** How much long does the test allow it to take */ private static final int ALLOWANCE = 2000; - // TODO: write unit test for new software update + @Test + public void testCompareLatest() throws UpdateInfoRetriever.UpdateInfoFetcher.UpdateCheckerException { + // Test normal official releases + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("14.03", "15.03")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "22.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "15.03")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "22.02.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.01", "22.02.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.01", "22.02")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "22.03")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "22.01")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "23")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02", "21")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22", "23")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22", "22")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22", "21")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.00", "22.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.00", "22.00")); + + + // Test alpha/beta releases + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.alpha.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.02", "22.02.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.beta.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.beta.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.02", "22.02.beta.01")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.01", "22.alpha.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.01", "22.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.02", "22.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.01", "22.beta.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.LATEST, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.01", "22.beta.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.02", "22.beta.01")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.01", "22.02.alpha.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.01", "22.02.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.alpha.02", "22.02.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.01", "22.02.beta.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.01", "22.02.beta.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.beta.02", "22.02.beta.01")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.beta.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.beta.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.02", "22.02.beta.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.alpha.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.alpha.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.02", "22.02.alpha.01")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.03")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.alpha.01", "22.02.02")); + + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.03")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.NEWER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.01")); + assertEquals(UpdateInfoRetriever.ReleaseStatus.OLDER, + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest("22.02.beta.01", "22.02.02")); + + + // Test bogus releases + assertExceptionCompareLatest("22.02.gamma.01", "22.02"); + assertExceptionCompareLatest(null, "22.02"); + assertExceptionCompareLatest("22.02", null); + assertExceptionCompareLatest(null, null); + assertExceptionCompareLatest("", "15.03"); + assertExceptionCompareLatest("22.02", ""); + assertExceptionCompareLatest(" ", "15.03"); + assertExceptionCompareLatest("22.02", " "); + assertExceptionCompareLatest("Hello", "22.02"); + assertExceptionCompareLatest("22.02", "world"); + assertExceptionCompareLatest("22.02", "15,03"); + assertExceptionCompareLatest("22..02", "15.03"); + assertExceptionCompareLatest("22.02", "15..03"); + assertExceptionCompareLatest("22.02a", "15.03"); + assertExceptionCompareLatest("22.02", "15.03b"); + assertExceptionCompareLatest("alpha.22.02", "15.03"); + assertExceptionCompareLatest("gamma.22.02", "15.03"); + assertExceptionCompareLatest("15.03", "alpha.22.02"); + assertExceptionCompareLatest("15.03", "gamma.22.02"); + assertExceptionCompareLatest("-22.02", "15.03"); + assertExceptionCompareLatest("22.-02", "15.03"); + assertExceptionCompareLatest("22.02", "-15.03"); + assertExceptionCompareLatest("22.02", "15.-03"); + } + + private void assertExceptionCompareLatest(String tag1, String tag2) { + try { + UpdateInfoRetriever.UpdateInfoFetcher.compareLatest(tag1, tag2); + fail("Should have thrown an exception"); + } catch (UpdateInfoRetriever.UpdateInfoFetcher.UpdateCheckerException e) { + // Expected + } + } + + @Test + public void testFilterReleaseTags() { + String[] temp = {"22.02", "22", "15.03", "0.1", "22.02.beta.01", "23.alpha.01", "20.beta.01", "22.gamma.01", + "beta.01", "alpha.02"}; + List releases = Arrays.asList(temp); + String[] expectedReleases = {"22.02.beta.01", "20.beta.01", "22.gamma.01", "beta.01"}; + + String[] filters = {"beta", "gamma"}; + List results = UpdateInfoRetriever.UpdateInfoFetcher.filterReleaseTags(releases, filters); + System.out.println(results); + assertEquals(" filtered results have different size", expectedReleases.length, results.size()); + for (String r : expectedReleases) { + assertTrue(String.format(" Filtered results does not contain %s", r), results.contains(r)); + } + + results = UpdateInfoRetriever.UpdateInfoFetcher.filterReleaseTags(releases, null); + assertEquals(" filtered results have different size", releases.size(), results.size()); + for (String r : releases) { + assertTrue(String.format(" Filtered results does not contain %s", r), results.contains(r)); + } + + assertNull(UpdateInfoRetriever.UpdateInfoFetcher.filterReleaseTags(null, null)); + } + + @Test + public void testFilterOfficialRelease() { + String[] temp = {"22.02", "22", "15.03", "0.1", "22.02.beta.01", "23.alpha.01", "20.gamma.01"}; + List releases = Arrays.asList(temp); + String[] expectedReleases = {"22.02", "22", "15.03", "0.1", "20.gamma.01"}; + + releases = UpdateInfoRetriever.UpdateInfoFetcher.filterOfficialRelease(releases); + assertEquals(" filtered results have different size", expectedReleases.length, releases.size()); + for (String r : expectedReleases) { + assertTrue(String.format(" Filtered results does not contain %s", r), releases.contains(r)); + } + + assertNull(UpdateInfoRetriever.UpdateInfoFetcher.filterOfficialRelease(null)); + } + + @Test + public void testFilterReleasePreTag() { + String[] temp = {"22.03", "22", "15.03", "0.2", "22.02.beta.01", "23.alpha.01", "20.gamma.01", + "android-22.02", "22-android", "15.03", "android-0.1", "android.22.02.beta.01", "android23.alpha.01", "20.gamma.01"}; + List releases = Arrays.asList(temp); + String[] expectedReleases = {"22.02", "0.1"}; + + List results = UpdateInfoRetriever.UpdateInfoFetcher.filterReleasePreTag(releases, "android"); + assertEquals(" filtered results have different size", expectedReleases.length, results.size()); + for (String r : expectedReleases) { + assertTrue(String.format(" Filtered results does not contain %s", r), results.contains(r)); + } + + assertNull(UpdateInfoRetriever.UpdateInfoFetcher.filterReleasePreTag(null, "android")); + assertNull(UpdateInfoRetriever.UpdateInfoFetcher.filterReleasePreTag(null, null)); + + expectedReleases = new String[]{"22.03", "22", "15.03", "0.2", "22.02.beta.01", "23.alpha.01", "20.gamma.01", + "15.03","20.gamma.01"}; + results = UpdateInfoRetriever.UpdateInfoFetcher.filterReleasePreTag(releases, null); + assertEquals(" filtered results have different size", expectedReleases.length, results.size()); + for (String r : expectedReleases) { + assertTrue(String.format(" Filtered results does not contain %s", r), results.contains(r)); + } + } + + @Test + public void testParseJsonArray() throws UpdateInfoRetriever.UpdateInfoFetcher.UpdateCheckerException { + JsonArray jsonArr = null; + JsonObject latestObj = UpdateInfoRetriever.UpdateInfoFetcher.getLatestReleaseJSON(jsonArr, null, null, false); + assertNull(latestObj); + + // Generate a dummy json array, containing GitHub release info + JsonArrayBuilder builder = Json.createArrayBuilder(); + JsonObjectBuilder objectBuilder = Json.createObjectBuilder(); + objectBuilder.add("tag_name", "release-22.02"); + objectBuilder.add("body", "Release notes"); + objectBuilder.add("html_url", "localhost"); + JsonArrayBuilder assetsBuilder = Json.createArrayBuilder(); + JsonObjectBuilder assetObject = Json.createObjectBuilder(); + assetObject.add("name", "OpenRocket-22.02-macOS.dmg"); + assetObject.add("browser_download_url", "https://github.com/openrocket/openrocket/releases/download/release-22.02/OpenRocket-22.02-macOS.dmg"); + assetsBuilder.add(assetObject.build()); + objectBuilder.add("assets", assetsBuilder.build()); + builder.add(objectBuilder.build()); + jsonArr = builder.build(); + + latestObj = UpdateInfoRetriever.UpdateInfoFetcher.getLatestReleaseJSON(jsonArr, null, null, false); + ReleaseInfo release = new ReleaseInfo(latestObj); + String latestName = release.getReleaseName(); + String releaseNotes = release.getReleaseNotes(); + String releaseUrl = release.getReleaseURL(); + List assetURLs = release.getAssetURLs(); + assertEquals("22.02", latestName); + assertEquals("Release notes", releaseNotes); + assertEquals("localhost", releaseUrl); + assertEquals(1, assetURLs.size()); + assertEquals("https://github.com/openrocket/openrocket/releases/download/release-22.02/OpenRocket-22.02-macOS.dmg", assetURLs.get(0)); + + // Test bogus releases + try { + new ReleaseInfo(null); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + + jsonArr = Json.createArrayBuilder().build(); + latestObj = UpdateInfoRetriever.UpdateInfoFetcher.getLatestReleaseJSON(jsonArr, null, null, false); + assertNull(latestObj); + + builder = Json.createArrayBuilder(); + builder.add(Json.createObjectBuilder().build()); + jsonArr = builder.build(); + try { + UpdateInfoRetriever.UpdateInfoFetcher.getLatestReleaseJSON(jsonArr, null, null, false); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + + release = new ReleaseInfo(Json.createObjectBuilder().build()); + try { + release.getReleaseName(); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + try { + release.getReleaseNotes(); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + try { + release.getReleaseURL(); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + try { + release.getAssetURLs(); + fail("Should have thrown NullPointerException"); + } catch (NullPointerException ignore) { } + } + + @Test + public void testFetchReleases() { + // TODO: fetch releases from GitHub (= test UpdateInfoRetriever.UpdateInfoFetcher.retrieveAllReleaseObjects) + } + + // TODO: these are the old unit tests; leaving them in to be used as reference for testFetchReleases() /*private HttpURLConnectionMock setup() { HttpURLConnectionMock connection = new HttpURLConnectionMock(); Communicator.setConnectionSource(new ConnectionSourceStub(connection)); - + connection.setConnectionDelay(DELAY); connection.setUseCaches(true); connection.setContentType("text/plain"); return connection; } - + private void check(HttpURLConnectionMock connection) { assertEquals(Communicator.UPDATE_URL + "?version=" + BuildProperties.getVersion(), connection.getTrueUrl()); @@ -51,13 +349,13 @@ public class UpdateInfoTest extends BaseTestCase { assertEquals("GET", connection.getRequestMethod()); assertFalse(connection.getUseCaches()); } - - + + @Test public void testUpdateAvailable() throws IOException { HttpURLConnectionMock connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE); - + String content = "Version: 6.6.6pre A \n" + "Extra: information\n" + @@ -66,23 +364,23 @@ public class UpdateInfoTest extends BaseTestCase { "1: one\n" + "-2: none"; connection.setContent(content); - + UpdateInfoRetriever retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); - + // Info is null while processing assertNull(retriever.getUpdateInfo()); - + waitfor(retriever); assertFalse(connection.hasFailed()); - + UpdateInfo info = retriever.getUpdateInfo(); assertNotNull(info); - + check(connection); - + assertEquals("6.6.6pre A", info.getLatestVersion()); - + List> updates = info.getUpdates(); assertEquals(3, updates.size()); Collections.sort(updates); @@ -93,15 +391,15 @@ public class UpdateInfoTest extends BaseTestCase { assertEquals(100, (int) updates.get(2).getU()); assertEquals("hundred", updates.get(2).getV()); } - - - - + + + + @Test public void testUpdateNotAvailable() throws IOException { HttpURLConnectionMock connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_NO_UPDATE_CODE); - + String content = "Version: 6.6.6pre A \n" + "Extra: information\n" + @@ -110,33 +408,33 @@ public class UpdateInfoTest extends BaseTestCase { "1: one\n" + "-2: none"; connection.setContent(content); - + UpdateInfoRetriever retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); - + // Info is null while processing assertNull(retriever.getUpdateInfo()); - + waitfor(retriever); assertFalse(connection.hasFailed()); - + UpdateInfo info = retriever.getUpdateInfo(); assertNotNull(info); - + check(connection); - + assertEquals(BuildProperties.getVersion(), info.getLatestVersion()); assertEquals(0, info.getUpdates().size()); } - - - + + + @Test public void testInvalidResponses() { HttpURLConnectionMock connection = setup(); connection.setResponseCode(404); connection.setContent("Version: 1.2.3"); - + UpdateInfoRetriever retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); assertNull(retriever.getUpdateInfo()); @@ -144,12 +442,12 @@ public class UpdateInfoTest extends BaseTestCase { assertFalse(connection.hasFailed()); assertNull(retriever.getUpdateInfo()); check(connection); - - + + connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE); connection.setContentType("text/xml"); - + retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); assertNull(retriever.getUpdateInfo()); @@ -157,9 +455,9 @@ public class UpdateInfoTest extends BaseTestCase { assertFalse(connection.hasFailed()); assertNull(retriever.getUpdateInfo()); check(connection); - - - + + + connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE); String content = @@ -167,7 +465,7 @@ public class UpdateInfoTest extends BaseTestCase { "50: m\u00e4 \n\n" + "1: one\n"; connection.setContent(content); - + retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); assertNull(retriever.getUpdateInfo()); @@ -175,12 +473,12 @@ public class UpdateInfoTest extends BaseTestCase { assertFalse(connection.hasFailed()); assertNull(retriever.getUpdateInfo()); check(connection); - - + + connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE); connection.setContent(new byte[0]); - + retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); assertNull(retriever.getUpdateInfo()); @@ -188,22 +486,22 @@ public class UpdateInfoTest extends BaseTestCase { assertFalse(connection.hasFailed()); assertNull(retriever.getUpdateInfo()); check(connection); - + } - + @Test public void testRandomInputData() { - + Random rnd = new Random(); for (int i = 0; i < 10; i++) { int size = Math.abs((int) ((1 + 0.3 * rnd.nextGaussian()) * Math.pow(i, 6))); byte[] buf = new byte[size]; rnd.nextBytes(buf); - + HttpURLConnectionMock connection = setup(); connection.setResponseCode(Communicator.UPDATE_INFO_UPDATE_AVAILABLE); connection.setContent(buf); - + UpdateInfoRetriever retriever = new UpdateInfoRetriever(); retriever.startFetchUpdateInfo(); assertNull(retriever.getUpdateInfo()); @@ -212,26 +510,26 @@ public class UpdateInfoTest extends BaseTestCase { assertNull(retriever.getUpdateInfo()); check(connection); } - + } - - - + + + private void waitfor(UpdateInfoRetriever retriever) { long t = System.currentTimeMillis(); - + while (retriever.isRunning()) { if (System.currentTimeMillis() >= t + ALLOWANCE) { fail("retriever took too long to respond"); } - + try { Thread.sleep(10); } catch (InterruptedException e) { } } - + //System.out.println("Waiting took " + (System.currentTimeMillis()-t) + " ms"); }*/ - + }