Skip to content

Commit 44547d0

Browse files
committed
Simplify ProblemBuilder#status method
1 parent 28f27d2 commit 44547d0

File tree

3 files changed

+116
-9
lines changed

3 files changed

+116
-9
lines changed

src/main/java/io/github/malczuuu/problem4j/core/ProblemBuilder.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ public interface ProblemBuilder {
4646
ProblemBuilder status(int status);
4747

4848
/**
49-
* Sets the HTTP status code using a {@link ProblemStatus} enum. It also sets {@link #title} if
50-
* not already assigned.
49+
* Sets the HTTP status code using a {@link ProblemStatus} enum.
5150
*
5251
* @param status the {@link ProblemStatus} representing the HTTP status
5352
* @return this builder instance for chaining
@@ -115,6 +114,20 @@ public interface ProblemBuilder {
115114
/**
116115
* Builds an immutable {@link Problem} instance with the configured properties and extensions.
117116
*
117+
* <p>Default value evaluation (all defaults are applied at build time):
118+
*
119+
* <ul>
120+
* <li>If no type was provided, the resulting {@code Problem} will use {@code
121+
* Problem#BLANK_TYPE}.
122+
* <li>If no title was provided, but the numeric status corresponds to a known {@code
123+
* ProblemStatus}, the builder will use the matching {@code ProblemStatus#getTitle()} as the
124+
* problem title.
125+
* <li>The numeric status defaults to <code>0</code> when not set; a title will not be derived
126+
* from status when it is <code>0</code> or when it does not map to any known {@code
127+
* ProblemStatus}.
128+
* <li>Any extensions configured on the builder will be present on the created {@code Problem}.
129+
* </ul>
130+
*
118131
* @return a new {@link Problem} instance
119132
*/
120133
Problem build();

src/main/java/io/github/malczuuu/problem4j/core/ProblemBuilderImpl.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,7 @@ public ProblemBuilder status(int status) {
4444

4545
@Override
4646
public ProblemBuilder status(ProblemStatus status) {
47-
if (status != null) {
48-
if (title == null) {
49-
title = status.getTitle();
50-
}
51-
this.status = status.getStatus();
52-
}
53-
return this;
47+
return status != null ? status(status.getStatus()) : status(0);
5448
}
5549

5650
@Override

src/test/java/io/github/malczuuu/problem4j/core/ProblemBuilderImplTests.java

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.malczuuu.problem4j.core;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
45

56
import java.net.URI;
67
import java.util.Arrays;
@@ -33,6 +34,51 @@ void givenNullProblemStatus_shouldNotSetTitleOrStatus() {
3334
assertThat(problem.getTitle()).isNull();
3435
}
3536

37+
@Test
38+
void givenProblemStatus_shouldSetNumericStatusAndTitle() {
39+
Problem problem = Problem.builder().status(ProblemStatus.BAD_REQUEST).build();
40+
41+
assertThat(problem.getStatus()).isEqualTo(ProblemStatus.BAD_REQUEST.getStatus());
42+
assertThat(problem.getTitle()).isEqualTo(ProblemStatus.BAD_REQUEST.getTitle());
43+
}
44+
45+
@Test
46+
void givenProblemStatus_shouldPreferExplicitStatusValueWhenSetEarlier() {
47+
Problem problem = Problem.builder().status(405).status(ProblemStatus.I_AM_A_TEAPOT).build();
48+
49+
assertThat(problem.getStatus()).isEqualTo(ProblemStatus.I_AM_A_TEAPOT.getStatus());
50+
assertThat(problem.getTitle()).isEqualTo(ProblemStatus.I_AM_A_TEAPOT.getTitle());
51+
}
52+
53+
@Test
54+
void givenExplicitTitle_thenStatusProblemStatus_shouldNotOverrideTitle() {
55+
Problem problem =
56+
Problem.builder().title("Custom Title").status(ProblemStatus.BAD_REQUEST).build();
57+
58+
assertThat(problem.getStatus()).isEqualTo(ProblemStatus.BAD_REQUEST.getStatus());
59+
assertThat(problem.getTitle()).isEqualTo("Custom Title");
60+
}
61+
62+
@Test
63+
void givenStatusProblemStatus_thenExplicitTitle_shouldOverrideDerivedTitle() {
64+
Problem problem = Problem.builder().status(ProblemStatus.NOT_FOUND).title("My Title").build();
65+
66+
assertThat(problem.getStatus()).isEqualTo(ProblemStatus.NOT_FOUND.getStatus());
67+
assertThat(problem.getTitle()).isEqualTo("My Title");
68+
}
69+
70+
@Test
71+
void givenInvalidTypeString_shouldThrowIllegalArgumentException() {
72+
assertThatThrownBy(() -> Problem.builder().type("ht tp://not a uri"))
73+
.isInstanceOf(IllegalArgumentException.class);
74+
}
75+
76+
@Test
77+
void givenInvalidInstanceString_shouldThrowIllegalArgumentException() {
78+
assertThatThrownBy(() -> Problem.builder().instance("::://invalid"))
79+
.isInstanceOf(IllegalArgumentException.class);
80+
}
81+
3682
@Test
3783
void givenNullURIInstance_shouldNotSetIt() {
3884
Problem problem = Problem.builder().instance((URI) null).build();
@@ -107,4 +153,58 @@ void givenCollectionWithNullElement_shouldIgnoreNullElement() {
107153

108154
assertThat(problem.getExtensions()).containsExactlyInAnyOrder("x", "y");
109155
}
156+
157+
@Test
158+
void numericStatus_shouldDeriveTitleWhenKnown() {
159+
Problem problem = Problem.builder().status(ProblemStatus.MULTI_STATUS.getStatus()).build();
160+
161+
assertThat(problem.getStatus()).isEqualTo(ProblemStatus.MULTI_STATUS.getStatus());
162+
assertThat(problem.getTitle()).isEqualTo(ProblemStatus.MULTI_STATUS.getTitle());
163+
}
164+
165+
@Test
166+
void unknownNumericStatus_shouldNotDeriveTitle() {
167+
Problem problem = Problem.builder().status(999).build();
168+
169+
assertThat(problem.getStatus()).isEqualTo(999);
170+
assertThat(problem.getTitle()).isNull();
171+
}
172+
173+
@Test
174+
void typeAndInstance_stringOverloads_shouldAcceptValidUris() {
175+
String t = "http://example.org/type";
176+
String i = "http://example.org/instance";
177+
178+
Problem problem = Problem.builder().type(t).instance(i).build();
179+
180+
assertThat(problem.getType()).isEqualTo(URI.create(t));
181+
assertThat(problem.getInstance()).isEqualTo(URI.create(i));
182+
}
183+
184+
@Test
185+
void emptyMapExtension_shouldBeIgnored() {
186+
Map<String, Object> m = new HashMap<>();
187+
Problem problem = Problem.builder().extension(m).build();
188+
189+
assertThat(problem.getExtensions()).isEmpty();
190+
}
191+
192+
@Test
193+
void nullValuedExtension_isPresentButOmittedFromToString() {
194+
Problem problem = Problem.builder().extension("ext", null).build();
195+
196+
assertThat(problem.getExtensions()).containsExactly("ext");
197+
assertThat(problem.getExtensionValue("ext")).isNull();
198+
199+
String s = problem.toString();
200+
assertThat(s).doesNotContain("\"ext\"");
201+
}
202+
203+
@Test
204+
void laterExtensions_shouldOverwriteEarlierValues() {
205+
Problem problem =
206+
Problem.builder().extension("k", "v1").extension(Problem.extension("k", "v2")).build();
207+
208+
assertThat(problem.getExtensionValue("k")).isEqualTo("v2");
209+
}
110210
}

0 commit comments

Comments
 (0)