Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support list of objects for JSON #693

Merged
merged 2 commits into from
Feb 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions src/main/java/net/datafaker/transformations/JsonTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public String apply(IN input, Schema<IN, ?> schema) {
if (fields[i] instanceof CompositeField) {
sb.append(apply(input, (CompositeField) fields[i], i));
} else {
value2String(((SimpleField) fields[i]).transform(input), sb);
applyValue(input, sb, ((SimpleField) fields[i]).transform(input));
}
if (i < fields.length - 1) {
sb.append(", ");
Expand Down Expand Up @@ -77,6 +77,35 @@ public String generate(Schema<IN, ?> schema, int limit) {
return limit > 1 ? wrappers[0] + LINE_SEPARATOR + sb + LINE_SEPARATOR + wrappers[1] : sb.toString();
}

private void applyValue(IN input, StringBuilder sb, Object value) {
if (value instanceof Collection<?>) {
sb.append(generate(input,(Collection) value));
} else if (value != null && value.getClass().isArray()) {
sb.append(generate(input, Arrays.asList((Object[]) value)));
} else {
value2String(value, sb);
}
}

private String generate(IN input, Collection<Object> collection) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int i = 0;
for (Object value : collection) {
if (i > 0) {
sb.append(", ");
}
i++;
if (value instanceof CompositeField<?,?>) {
sb.append(apply(input,((CompositeField) value)));
} else {
applyValue(input, sb, value);
}
}
sb.append("]");
return sb.toString();
}

private static void value2String(Object value, StringBuilder sb) {
if (value == null) {
sb.append("null");
Expand All @@ -90,10 +119,6 @@ private static void value2String(Object value, StringBuilder sb) {
|| (value instanceof BigDecimal
&& ((BigDecimal) value).remainder(BigDecimal.ONE).doubleValue() == 0)) {
sb.append(value);
} else if (value instanceof Collection) {
sb.append(generate((Collection) value));
} else if (value.getClass().isArray()) {
sb.append(generate(Arrays.asList((Object[]) value)));
} else {
String val = String.valueOf(value);
boolean toWrap = !val.startsWith("#{json");
Expand All @@ -109,22 +134,6 @@ private static void value2String(Object value, StringBuilder sb) {
}
}

private static String generate(Collection<Object> collection) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int i = 0;
for (Object value : collection) {
if (i > 0) {
sb.append(", ");
}
i++;
value2String(value, sb);
}
sb.append("]");
return sb.toString();
}


private static Map<Character, String> createEscapeMap() {
final Map<Character, String> map = new HashMap<>();
map.put('\\', "\\\\");
Expand Down
85 changes: 85 additions & 0 deletions src/test/java/net/datafaker/formats/JsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
import java.util.AbstractMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Stream;
import net.datafaker.providers.base.BaseFaker;
import net.datafaker.providers.base.Name;
import net.datafaker.sequence.FakeSequence;
import net.datafaker.transformations.Field;
import net.datafaker.transformations.JsonTransformer;
Expand Down Expand Up @@ -255,6 +257,89 @@ private static Stream<Arguments> generateTestJson() {
"{\"key\": \"value\", \"nested\": {\"nestedkey\": \"nestedvalue\"}}"));
}

@Test
void jsonWithDifferentFieldFormatsInOneObjectTest() {
BaseFaker faker = new BaseFaker(new Random(10L));
final int limit = 2;
JsonTransformer<Object> transformer = JsonTransformer.builder().build();

String json = transformer.generate(
faker.collection().minLen(limit).maxLen(limit)
.suppliers(faker::name)
.build(), Schema.<Object, Object>of(
field("text", () -> faker.name().firstName()),
field("array", () ->
faker
.collection()
.suppliers(() -> faker.phoneNumber().phoneNumber())
.maxLen(3)
.generate()
)
));

int numberOfLines = 0;
for (int i = 0; i < json.length(); i++) {
if (json.regionMatches(i, "},", 0, "},".length())) {
numberOfLines++;
}
}
assertThat(numberOfLines).isEqualTo(limit - 1);
}

@Test
void jsonObjectCollectionTest() {
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().build();

String json = transformer.generate(
Schema.of(
field("text", () -> "Mrs. Brian Braun"),
field("objectCollection", () -> List.of(
compositeField(null, new Field[]{
field("country", () -> "Denmark"),
field("city", () -> "Port Angel")
}
),
compositeField(null, new Field[]{
field("two", () -> "Denmark"),
field("one", () -> "Port Angel")
}
)
)
)
), 1);
assertThat(json).isEqualTo("{\"text\": \"Mrs. Brian Braun\", " +
"\"objectCollection\": [{\"country\": \"Denmark\", \"city\": \"Port Angel\"}, {\"two\": \"Denmark\", \"one\": \"Port Angel\"}]}");
}

@Test
void jsonCollectionOfCollectionsTest() {
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().build();

String json = transformer.generate(
Schema.of(
field("text", () -> "Mrs. Brian Braun"),
field("objectCollection", () -> List.of(
List.of(
List.of(
compositeField(null, new Field[]{
field("country", () -> "Denmark"),
field("city", () -> "Port Angel")
}
),
compositeField(null, new Field[]{
field("two", () -> "Denmark"),
field("one", () -> "Port Angel")
}
)
)
)
)
)
), 1);
assertThat(json).isEqualTo("{\"text\": \"Mrs. Brian Braun\", " +
"\"objectCollection\": [[[{\"country\": \"Denmark\", \"city\": \"Port Angel\"}, {\"two\": \"Denmark\", \"one\": \"Port Angel\"}]]]}");
}

private static Map.Entry<Supplier<String>, Supplier<Object>> entry(
Supplier<String> key, Supplier<Object> value) {
return new AbstractMap.SimpleEntry<>(key, value);
Expand Down
63 changes: 36 additions & 27 deletions src/test/java/net/datafaker/sequence/FakeCollectionTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package net.datafaker.sequence;

import net.datafaker.AbstractFakerTest;
import net.datafaker.formats.Format;
import net.datafaker.providers.base.Address;
import net.datafaker.providers.base.BaseFaker;
import net.datafaker.providers.base.Name;
import net.datafaker.providers.base.Number;
import net.datafaker.transformations.CompositeField;
import net.datafaker.transformations.CsvTransformer;
import net.datafaker.transformations.Field;
import net.datafaker.transformations.JsonTransformer;
import net.datafaker.transformations.Schema;
import org.junit.jupiter.api.RepeatedTest;
Expand All @@ -18,6 +20,7 @@
import java.util.Random;
import java.util.function.Supplier;

import static net.datafaker.transformations.Field.compositeField;
import static net.datafaker.transformations.Field.field;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand Down Expand Up @@ -222,36 +225,42 @@ void toJson() {
@Test
void toNestedJson() {
final int limit = 2;
final String json =
Format.toJson(faker.collection()
.suppliers(faker::name)
.maxLen(limit)
.minLen(limit)
.build())
.set("primaryAddress", Format.toJson()
.set("country", () -> faker.address().country())
.set("city", () -> faker.address().city())
.set("zipcode", () -> faker.address().zipCode())
.set("streetAddress", () -> faker.address().streetAddress())
.build())
.set("secondaryAddresses", Format.toJson(faker.<Address>collection()
.suppliers(faker::address)
.maxLen(1)
.minLen(1)
.build())
.set("country", Address::country)
.set("city", Address::city)
.set("zipcode", Address::zipCode)
.set("streetAddress", Address::streetAddress)
.build())
.set("phones", name -> faker.collection().suppliers(() -> faker.phoneNumber().phoneNumber()).maxLen(3).build().get())
.build()
.generate();
JsonTransformer<Name> transformer = JsonTransformer.<Name>builder().formattedAs(JsonTransformer.JsonTransformerBuilder.FormattedAs.JSON_ARRAY).build();

FakeSequence<CompositeField<Address, String>> secondaryAddresses =
faker.<CompositeField<Address, String>>collection()
.suppliers(() ->
compositeField(null, new Field[]{
field("country", () -> faker.address().country()),
field("city", () -> faker.address().city()),
field("zipcode", () -> faker.address().zipCode()),
field("streetAddress", () -> faker.address().streetAddress())
})
)
.maxLen(1)
.minLen(1)
.build();

String json = transformer.generate(
faker.<Name>collection().minLen(limit).maxLen(limit)
.suppliers(faker::name)
.build(),
Schema.of(
compositeField("primaryAddress", new Field[]{
field("country", () -> faker.address().country()),
field("city", () -> faker.address().city()),
field("zipcode", () -> faker.address().zipCode()),
field("streetAddress", () -> faker.address().streetAddress())
}),
field("secondaryAddresses", secondaryAddresses::get),
field("phones", name -> faker.collection().suppliers(() -> faker.phoneNumber().phoneNumber()).maxLen(3).build().get())
));


System.out.println(json);
int numberOfLines = 0;
for (int i = 0; i < json.length(); i++) {
if (json.regionMatches(i, System.lineSeparator(), 0, System.lineSeparator().length())) {
if (json.regionMatches(i, "}," + System.lineSeparator(), 0, ("}," + System.lineSeparator()).length())) {
numberOfLines++;
}
}
Expand Down