diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java index 2ad4a0fd..d1b31085 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Endpoint.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Endpoint implements Model { +public final class Endpoint implements Model, HasId { @JsonProperty private long id; @@ -49,10 +49,11 @@ public final class Endpoint implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - return queryParams.containsKey("id") && queryParams.get("id").equals(this.id); + return QueryParamsComparator.isIdEqual(this, queryParams); } + } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Engagement.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Engagement.java index 25f1c6a3..16a7d80a 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Engagement.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Engagement.java @@ -17,12 +17,12 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Engagement implements Model { +public final class Engagement implements Model, HasId, HasName { @JsonProperty("branch_tag") private String branch; @JsonProperty - private Long id; + private long id; @JsonProperty private String name; @@ -94,15 +94,15 @@ public final class Engagement implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id") != null && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name") != null && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Finding.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Finding.java index 426fe6e2..1e3677eb 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Finding.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Finding.java @@ -21,7 +21,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Finding implements Model { +public final class Finding implements Model, HasId { @JsonProperty private long id; @@ -121,11 +121,11 @@ public String getNumericalSeverity() { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - return queryParams.containsKey("id") && queryParams.get("id").equals(this.id); + return QueryParamsComparator.isIdEqual(this, queryParams); } public enum Severity { diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Group.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Group.java index 7f96bd15..3d7e0f5c 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Group.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Group.java @@ -17,7 +17,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Group implements Model { +public final class Group implements Model, HasId, HasName { @JsonProperty private long id; @@ -36,15 +36,15 @@ public final class Group implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/HasId.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/HasId.java new file mode 100644 index 00000000..8c8e1092 --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/HasId.java @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package io.securecodebox.persistence.defectdojo.model; + +/** + * Interface to mark {@link Model models} which have an id + *

+ * This type is package private because it is an implementation detail of the models and + * z should not be used outside of this package. + *

+ */ +interface HasId { + long getId(); + + void setId(long id); +} diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/HasName.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/HasName.java new file mode 100644 index 00000000..6d5b9a3a --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/HasName.java @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package io.securecodebox.persistence.defectdojo.model; + +/** + * Interface to mark {@link Model models} which have a name + *

+ * This type is package private because it is an implementation detail of the models and + * z should not be used outside of this package. + *

+ */ +interface HasName { + String getName(); + + void setName(String id); +} diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Product.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Product.java index 2f703153..f5cb2824 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Product.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Product.java @@ -17,7 +17,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Product implements Model { +public final class Product implements Model, HasId, HasName { @JsonProperty private long id; @@ -53,15 +53,15 @@ public final class Product implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/ProductType.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/ProductType.java index 38fbb893..6aac466e 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/ProductType.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/ProductType.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class ProductType implements Model { +public final class ProductType implements Model, HasId, HasName { @JsonProperty private long id; @@ -32,15 +32,15 @@ public final class ProductType implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java new file mode 100644 index 00000000..bcc30c6b --- /dev/null +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparator.java @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package io.securecodebox.persistence.defectdojo.model; + +import java.util.Map; + +/** + * Pure static helper class + *

+ * This type is package private because it is an implementation detail of the models and + * should not be used outside of this package. + *

+ */ +final class QueryParamsComparator { + + static final String QUERY_PARAM_KEY_FOR_ID = "id"; + static final String QUERY_PARAM_KEY_FOR_NAME = "name"; + + private QueryParamsComparator() { + super(); + } + + static boolean isNull(Object o) { + return o == null; + } + + static boolean isIdEqual(HasId model, Map queryParams) { + if (isNull(model)) { + return false; + } + + if (isNull(queryParams)) { + return false; + } + + if (!queryParams.containsKey(QUERY_PARAM_KEY_FOR_ID)) { + return false; + } + + // FIXME: Since th generic type for value is Object, possible NPE here! + return queryParams.get(QUERY_PARAM_KEY_FOR_ID).equals(model.getId()); + } + + static boolean isNameEqual(HasName model, Map queryParams) { + if (isNull(model)) { + return false; + } + + if (isNull(queryParams)) { + return false; + } + + if (!queryParams.containsKey(QUERY_PARAM_KEY_FOR_NAME)) { + return false; + } + + if (isNull(queryParams.get(QUERY_PARAM_KEY_FOR_NAME))) { + return false; + } + + return queryParams.get(QUERY_PARAM_KEY_FOR_NAME).equals(model.getName()); + } +} diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/RiskAcceptance.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/RiskAcceptance.java index 2fa127fc..fe6bc08f 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/RiskAcceptance.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/RiskAcceptance.java @@ -17,7 +17,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class RiskAcceptance implements Model { +public final class RiskAcceptance implements Model, HasId { @JsonProperty private long id; @@ -58,10 +58,10 @@ public final class RiskAcceptance implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - return queryParams.containsKey("id") && queryParams.get("id").equals(this.id); + return QueryParamsComparator.isIdEqual(this, queryParams); } } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/Test.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/Test.java index adb6a5cd..4b378fba 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/Test.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/Test.java @@ -18,7 +18,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class Test implements Model { +public final class Test implements Model, HasId { @JsonProperty private long id; @@ -63,11 +63,11 @@ public final class Test implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/TestType.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/TestType.java index 28864aee..a1cff33a 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/TestType.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/TestType.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class TestType implements Model { +public final class TestType implements Model, HasId, HasName { @JsonProperty private long id; @@ -33,15 +33,15 @@ public final class TestType implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolConfig.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolConfig.java index 60917d60..9992ae36 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolConfig.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolConfig.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class ToolConfig implements Model { +public final class ToolConfig implements Model, HasId, HasName { @JsonProperty private long id; @@ -38,15 +38,15 @@ public final class ToolConfig implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolType.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolType.java index ed1a008b..e4e14213 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolType.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/ToolType.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class ToolType implements Model { +public final class ToolType implements Model, HasId, HasName { @JsonProperty private long id; @@ -29,15 +29,15 @@ public final class ToolType implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } - if (queryParams.containsKey("name") && queryParams.get("name").equals(this.name)) { + if (QueryParamsComparator.isNameEqual(this, queryParams)) { return true; } diff --git a/src/main/java/io/securecodebox/persistence/defectdojo/model/User.java b/src/main/java/io/securecodebox/persistence/defectdojo/model/User.java index fecb30f1..737be18d 100644 --- a/src/main/java/io/securecodebox/persistence/defectdojo/model/User.java +++ b/src/main/java/io/securecodebox/persistence/defectdojo/model/User.java @@ -16,7 +16,7 @@ @AllArgsConstructor @EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) -public final class User implements Model { +public final class User implements Model, HasId { @JsonProperty private long id; @@ -32,11 +32,11 @@ public final class User implements Model { @Override public boolean equalsQueryString(Map queryParams) { - if (queryParams == null) { + if (QueryParamsComparator.isNull(queryParams)) { return false; } - if (queryParams.containsKey("id") && queryParams.get("id").equals(this.id)) { + if (QueryParamsComparator.isIdEqual(this, queryParams)) { return true; } diff --git a/src/test/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparatorTest.java b/src/test/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparatorTest.java new file mode 100644 index 00000000..956e9e07 --- /dev/null +++ b/src/test/java/io/securecodebox/persistence/defectdojo/model/QueryParamsComparatorTest.java @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package io.securecodebox.persistence.defectdojo.model; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link QueryParamsComparator} + */ +class QueryParamsComparatorTest { + @Test + void isNull() { + assertAll( + () -> assertThat(QueryParamsComparator.isNull(null), is(true)), + () -> assertThat(QueryParamsComparator.isNull(Collections.emptyMap()), is(false)) + ); + } + + @Test + void isIdEqual_falseIfModelIsNull() { + assertThat( + QueryParamsComparator.isIdEqual(null, Collections.emptyMap()), + is(false)); + } + + @Test + void isIdEqual_falseIfQueryParamsIsNull() { + assertThat( + QueryParamsComparator.isIdEqual(mock(HasId.class), null), + is(false)); + } + + @Test + void isIdEqual_falseIfQueryParamsDoesNotContainId() { + assertThat( + QueryParamsComparator.isIdEqual(mock(HasId.class), Collections.emptyMap()), + is(false)); + } + + @Test + @Disabled("Unclear if this behaviour will break something.") + void isIdEqual_falseIfQueryParamValueIsNull() { + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_ID, null); + + assertThat( + QueryParamsComparator.isIdEqual(mock(HasId.class), queryParams), + is(false)); + } + + @Test + void isIdEqual_trueForSameNumbers() { + final var model = mock(HasId.class); + when(model.getId()).thenReturn(42L); + + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_ID, 42L); + + assertThat( + QueryParamsComparator.isIdEqual(model, queryParams), + is(true)); + } + + @Test + void isIdEqual_falseForDifferentNumbers() { + final var model = mock(HasId.class); + when(model.getId()).thenReturn(42L); + + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_ID, 23L); + + assertThat( + QueryParamsComparator.isIdEqual(mock(HasId.class), queryParams), + is(false)); + } + + @Test + void isNameEqual_falseIfModelIsNull() { + assertThat( + QueryParamsComparator.isNameEqual(null, Collections.emptyMap()), + is(false)); + } + + @Test + void isNameEqual_falseIfQueryParamsIsNull() { + assertThat( + QueryParamsComparator.isNameEqual(mock(HasName.class), null), + is(false)); + } + + @Test + void isNameEqual_falseIfQueryParamsDoesNotContainId() { + assertThat( + QueryParamsComparator.isNameEqual(mock(HasName.class), Collections.emptyMap()), + is(false)); + } + + @Test + void isNameEqual_falseIfQueryParamValueIsNull() { + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_NAME, null); + + assertThat( + QueryParamsComparator.isNameEqual(mock(HasName.class), queryParams), + is(false)); + } + + @Test + void isNameEqual_trueForSameValues() { + final var model = mock(HasName.class); + when(model.getName()).thenReturn("foobar"); + + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_NAME, "foobar"); + + assertThat( + QueryParamsComparator.isNameEqual(model, queryParams), + is(true)); + } + + @Test + void isNameEqual_falseForDifferentValues() { + final var model = mock(HasName.class); + when(model.getName()).thenReturn("foobar"); + + final var queryParams = new HashMap(); + queryParams.put(QueryParamsComparator.QUERY_PARAM_KEY_FOR_NAME, "snafu"); + + assertThat( + QueryParamsComparator.isNameEqual(model, queryParams), + is(false)); + } +}