-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
34c8ba3
commit 3258ed9
Showing
7 changed files
with
264 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package com.cosium.hal_mock_mvc; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
/** | ||
* @author Réda Housni Alaoui | ||
*/ | ||
public class Form { | ||
|
||
private final RequestExecutor requestExecutor; | ||
private final ObjectMapper objectMapper; | ||
private final Template template; | ||
|
||
private final Map<String, FormProperty<?>> propertyByName = new HashMap<>(); | ||
|
||
Form(RequestExecutor requestExecutor, ObjectMapper objectMapper, Template template) { | ||
this.requestExecutor = requireNonNull(requestExecutor); | ||
this.objectMapper = requireNonNull(objectMapper); | ||
this.template = requireNonNull(template); | ||
} | ||
|
||
public Form withStringValue(String propertyName, String value) throws Exception { | ||
FormProperty<?> property = | ||
new FormProperty<>(String.class, propertyName, List.of(value), false); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withBooleanValue(String propertyName, Boolean value) throws Exception { | ||
FormProperty<?> property = | ||
new FormProperty<>(Boolean.class, propertyName, List.of(value), false); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withIntegerValue(String propertyName, Integer value) throws Exception { | ||
FormProperty<?> property = | ||
new FormProperty<>(Integer.class, propertyName, List.of(value), false); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withLongValue(String propertyName, Long value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(Long.class, propertyName, List.of(value), false); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withDoubleValue(String propertyName, Double value) throws Exception { | ||
FormProperty<?> property = | ||
new FormProperty<>(Double.class, propertyName, List.of(value), false); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withStringValues(String propertyName, List<String> value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(String.class, propertyName, value, true); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withBooleanValues(String propertyName, List<Boolean> value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(Boolean.class, propertyName, value, true); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withIntValues(String propertyName, List<Integer> value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(Integer.class, propertyName, value, true); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withLongValues(String propertyName, List<Long> value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(Long.class, propertyName, value, true); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
public Form withDoubleValues(String propertyName, List<Double> value) throws Exception { | ||
FormProperty<?> property = new FormProperty<>(Double.class, propertyName, value, true); | ||
propertyByName.put(property.name(), assertValid(property)); | ||
return this; | ||
} | ||
|
||
private FormProperty<?> assertValid(FormProperty<?> property) throws Exception { | ||
return new TemplateProperty(requestExecutor, objectMapper, requireTemplate(property)) | ||
.assertValid(property); | ||
} | ||
|
||
private TemplatePropertyRepresentation requireTemplate(FormProperty<?> property) { | ||
return Optional.ofNullable(template.representation().propertyByName().get(property.name())) | ||
.orElseThrow( | ||
() -> | ||
new IllegalArgumentException( | ||
"No property found for name '%s'".formatted(property.name()))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.cosium.hal_mock_mvc; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* @author Réda Housni Alaoui | ||
*/ | ||
record FormProperty<T>(Class<T> valueType, String name, List<T> values, boolean array) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
core/src/main/java/com/cosium/hal_mock_mvc/TemplateProperty.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package com.cosium.hal_mock_mvc; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import com.cosium.hal_mock_mvc.template.options.InlineElementRepresentation; | ||
import com.cosium.hal_mock_mvc.template.options.MapInlineElementRepresentation; | ||
import com.cosium.hal_mock_mvc.template.options.OptionsLinkRepresentation; | ||
import com.cosium.hal_mock_mvc.template.options.OptionsRepresentation; | ||
import com.cosium.hal_mock_mvc.template.options.StringInlineElementRepresentation; | ||
import com.fasterxml.jackson.core.type.TypeReference; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import java.util.List; | ||
import org.springframework.hateoas.Link; | ||
|
||
/** | ||
* @author Réda Housni Alaoui | ||
*/ | ||
class TemplateProperty { | ||
|
||
private final RequestExecutor requestExecutor; | ||
private final ObjectMapper objectMapper; | ||
private final TemplatePropertyRepresentation representation; | ||
|
||
TemplateProperty( | ||
RequestExecutor requestExecutor, | ||
ObjectMapper objectMapper, | ||
TemplatePropertyRepresentation representation) { | ||
this.requestExecutor = requireNonNull(requestExecutor); | ||
this.objectMapper = requireNonNull(objectMapper); | ||
this.representation = requireNonNull(representation); | ||
} | ||
|
||
public FormProperty<?> assertValid(FormProperty<?> property) throws Exception { | ||
OptionsRepresentation options = representation.options().orElse(null); | ||
if (options != null) { | ||
return assertValid(options, property); | ||
} | ||
return property; | ||
} | ||
|
||
private FormProperty<?> assertValid(OptionsRepresentation options, FormProperty<?> property) | ||
throws Exception { | ||
if (!String.class.equals(property.valueType())) { | ||
throw new IllegalArgumentException( | ||
"Cannot set a value of type '%s' because property '%s' expects a value from an enumeration of options." | ||
.formatted(property.valueType(), property.name())); | ||
} | ||
|
||
List<InlineElementRepresentation> inlineElements = options.inline().orElse(null); | ||
if (inlineElements != null) { | ||
assertValuesAreValidOptions(property, options, inlineElements); | ||
return property; | ||
} | ||
|
||
OptionsLinkRepresentation optionsLink = options.link().orElse(null); | ||
if (optionsLink == null) { | ||
throw new IllegalArgumentException( | ||
"Missing inline and remote elements from options %s.".formatted(options)); | ||
} | ||
|
||
assertValuesAreValidOptions(property, options, fetchRemoteElements(optionsLink)); | ||
return property; | ||
} | ||
|
||
private List<InlineElementRepresentation> fetchRemoteElements( | ||
OptionsLinkRepresentation optionsLink) throws Exception { | ||
|
||
String optionsHref = Link.of(optionsLink.href()).expand().toUri().toString(); | ||
|
||
String rawOptions = | ||
requestExecutor | ||
.execute(get(optionsHref)) | ||
.andExpect(status().is2xxSuccessful()) | ||
.andReturn() | ||
.getResponse() | ||
.getContentAsString(); | ||
|
||
return objectMapper.readValue(rawOptions, new TypeReference<>() {}); | ||
} | ||
|
||
private void assertValuesAreValidOptions( | ||
FormProperty<?> property, | ||
OptionsRepresentation options, | ||
List<InlineElementRepresentation> inlineElements) { | ||
|
||
if (inlineElements.isEmpty()) { | ||
throw new IllegalArgumentException( | ||
"Value of property '%s' cannot be non null because the list of available option is empty." | ||
.formatted(property.name())); | ||
} | ||
|
||
String valueField = options.valueField().orElse("value"); | ||
|
||
for (Object value : property.values()) { | ||
boolean match = | ||
inlineElements.stream() | ||
.anyMatch( | ||
inlineElement -> { | ||
if (inlineElement | ||
instanceof MapInlineElementRepresentation mapInlineElementRepresentation) { | ||
|
||
return value.equals(mapInlineElementRepresentation.map().get(valueField)); | ||
|
||
} else if (inlineElement | ||
instanceof | ||
StringInlineElementRepresentation stringInlineElementRepresentation) { | ||
|
||
return value.equals(stringInlineElementRepresentation.value()); | ||
|
||
} else { | ||
throw new IllegalArgumentException( | ||
"Unexpected type %s".formatted(inlineElement.getClass())); | ||
} | ||
}); | ||
|
||
if (match) { | ||
continue; | ||
} | ||
|
||
throw new IllegalArgumentException( | ||
"Value '%s' didn't match any inline option of property '%s' among %s" | ||
.formatted(value, property.name(), inlineElements)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters