diff --git a/core/src/main/java/google/registry/model/eppcommon/Address.java b/core/src/main/java/google/registry/model/eppcommon/Address.java index 423c71de9..ddb98101c 100644 --- a/core/src/main/java/google/registry/model/eppcommon/Address.java +++ b/core/src/main/java/google/registry/model/eppcommon/Address.java @@ -155,6 +155,7 @@ public class Address extends ImmutableObject @Override public void postProcess() { + validateState(); if (street == null || street.isEmpty()) { return; } @@ -163,6 +164,21 @@ public class Address extends ImmutableObject streetLine3 = street.size() >= 3 ? street.get(2) : null; } + public void validateState() { + checkArgument( + street == null || (!street.isEmpty() && street.size() <= 3), + "Street address must have [1-3] lines: %s", + street); + //noinspection ConstantConditions + checkArgument( + street == null || street.stream().noneMatch(String::isEmpty), + "Street address cannot contain empty string: %s", + street); + checkArgument( + countryCode == null || countryCode.length() == 2, + "Country code should be a 2 character string"); + } + /** A builder for constructing {@link Address}. */ public static class Builder extends Buildable.Builder { @@ -172,16 +188,13 @@ public class Address extends ImmutableObject super(instance); } + @Override + public T build() { + getInstance().validateState(); + return super.build(); + } + public Builder setStreet(ImmutableList street) { - checkArgument( - street == null || (!street.isEmpty() && street.size() <= 3), - "Street address must have [1-3] lines: %s", - street); - //noinspection ConstantConditions - checkArgument( - street.stream().noneMatch(String::isEmpty), - "Street address cannot contain empty string: %s", - street); getInstance().street = street; getInstance().streetLine1 = street.get(0); getInstance().streetLine2 = street.size() >= 2 ? street.get(1) : null; diff --git a/core/src/main/java/google/registry/model/registrar/RegistrarAddress.java b/core/src/main/java/google/registry/model/registrar/RegistrarAddress.java index 521a38264..eddb1027c 100644 --- a/core/src/main/java/google/registry/model/registrar/RegistrarAddress.java +++ b/core/src/main/java/google/registry/model/registrar/RegistrarAddress.java @@ -37,6 +37,14 @@ public class RegistrarAddress extends Address { return new Builder(clone(this)); } + @Override + public void validateState() { + super.validateState(); + checkNotNull(forceEmptyToNull(getStreet()), "Missing street"); + checkNotNull(getCity(), "Missing city"); + checkNotNull(getCountryCode(), "Missing country code"); + } + /** Builder for {@link RegistrarAddress}. */ public static class Builder extends Address.Builder { public Builder() {} @@ -44,14 +52,5 @@ public class RegistrarAddress extends Address { private Builder(RegistrarAddress instance) { super(instance); } - - @Override - public RegistrarAddress build() { - RegistrarAddress instance = getInstance(); - checkNotNull(forceEmptyToNull(instance.getStreet()), "Missing street"); - checkNotNull(instance.getCity(), "Missing city"); - checkNotNull(instance.getCountryCode(), "Missing country code"); - return super.build(); - } } } diff --git a/core/src/test/java/google/registry/model/eppcommon/AddressTest.java b/core/src/test/java/google/registry/model/eppcommon/AddressTest.java index 96ca1466d..f9c92818c 100644 --- a/core/src/test/java/google/registry/model/eppcommon/AddressTest.java +++ b/core/src/test/java/google/registry/model/eppcommon/AddressTest.java @@ -25,6 +25,7 @@ import google.registry.model.ImmutableObject; import google.registry.model.eppcommon.AddressTest.TestEntity.TestAddress; import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension; +import google.registry.tools.GsonUtils; import jakarta.persistence.Embeddable; import jakarta.persistence.Entity; import jakarta.persistence.Id; @@ -124,6 +125,38 @@ class AddressTest { assertAddress(unmarshalledEntity.address, "123 W 14th St", "8th Fl", "Rm 8"); } + @Test + void testSuccess_gsonInstantiation() { + String json = "{\"street\":[\"123 W 14th St\",\"8th Fl\"],\"countryCode\":\"US\"}"; + TestAddress address = GsonUtils.provideGson().fromJson(json, TestAddress.class); + assertThat(address.getStreet()).containsExactly("123 W 14th St", "8th Fl"); + assertThat(address.getCountryCode()).isEqualTo("US"); + } + + @Test + void testFailure_gsonInstantiation_tooManyStreetLines() { + String json = "{\"street\":[\"123 W 14th St\",\"8th Fl\",\"Rm 8\",\"4th Line\"]}"; + assertThrows( + IllegalArgumentException.class, + () -> GsonUtils.provideGson().fromJson(json, TestAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_emptyStreetLine() { + String json = "{\"street\":[\"123 W 14th St\",\"\"]}"; + assertThrows( + IllegalArgumentException.class, + () -> GsonUtils.provideGson().fromJson(json, TestAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_invalidCountryCode() { + String json = "{\"countryCode\":\"USA\"}"; + assertThrows( + IllegalArgumentException.class, + () -> GsonUtils.provideGson().fromJson(json, TestAddress.class)); + } + private static TestAddress createAddress(String... streetList) { return new TestAddress.Builder() .setStreet(ImmutableList.copyOf(streetList)) diff --git a/core/src/test/java/google/registry/model/registrar/RegistrarAddressTest.java b/core/src/test/java/google/registry/model/registrar/RegistrarAddressTest.java new file mode 100644 index 000000000..097be6186 --- /dev/null +++ b/core/src/test/java/google/registry/model/registrar/RegistrarAddressTest.java @@ -0,0 +1,94 @@ +// Copyright 2026 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.model.registrar; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.google.common.collect.ImmutableList; +import google.registry.tools.GsonUtils; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link RegistrarAddress}. */ +class RegistrarAddressTest { + + @Test + void testSuccess_gsonInstantiation() { + String json = "{\"street\":[\"123 W 14th St\"],\"city\":\"New York\",\"countryCode\":\"US\"}"; + RegistrarAddress address = GsonUtils.provideGson().fromJson(json, RegistrarAddress.class); + assertThat(address.getStreet()).containsExactly("123 W 14th St"); + assertThat(address.getCity()).isEqualTo("New York"); + assertThat(address.getCountryCode()).isEqualTo("US"); + } + + @Test + void testFailure_gsonInstantiation_missingStreet() { + String json = "{\"city\":\"New York\",\"countryCode\":\"US\"}"; + assertThrows( + NullPointerException.class, + () -> GsonUtils.provideGson().fromJson(json, RegistrarAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_missingCity() { + String json = "{\"street\":[\"123 W 14th St\"],\"countryCode\":\"US\"}"; + assertThrows( + NullPointerException.class, + () -> GsonUtils.provideGson().fromJson(json, RegistrarAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_missingCountryCode() { + String json = "{\"street\":[\"123 W 14th St\"],\"city\":\"New York\"}"; + assertThrows( + NullPointerException.class, + () -> GsonUtils.provideGson().fromJson(json, RegistrarAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_invalidCountryCode() { + String json = "{\"street\":[\"123 W 14th St\"],\"city\":\"New York\",\"countryCode\":\"USA\"}"; + assertThrows( + IllegalArgumentException.class, + () -> GsonUtils.provideGson().fromJson(json, RegistrarAddress.class)); + } + + @Test + void testFailure_gsonInstantiation_tooManyStreetLines() { + String json = + "{\"street\":[\"1\",\"2\",\"3\",\"4\"],\"city\":\"New York\",\"countryCode\":\"US\"}"; + assertThrows( + IllegalArgumentException.class, + () -> GsonUtils.provideGson().fromJson(json, RegistrarAddress.class)); + } + + @Test + void testSuccess_builder() { + RegistrarAddress address = + new RegistrarAddress.Builder() + .setStreet(ImmutableList.of("123 W 14th St")) + .setCity("New York") + .setCountryCode("US") + .build(); + assertThat(address.getStreet()).containsExactly("123 W 14th St"); + } + + @Test + void testFailure_builder_missingStreet() { + assertThrows( + NullPointerException.class, + () -> new RegistrarAddress.Builder().setCity("New York").setCountryCode("US").build()); + } +}