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

Add test of deterministic and non deterministic provider's methods #743

Merged
merged 3 commits into from Mar 29, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/net/datafaker/annotations/Deterministic.java
@@ -0,0 +1,12 @@
package net.datafaker.annotations;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Deterministic {
}
3 changes: 3 additions & 0 deletions src/main/java/net/datafaker/providers/base/Address.java
@@ -1,5 +1,7 @@
package net.datafaker.providers.base;

import net.datafaker.annotations.Deterministic;

/**
* @since 0.8.0
*/
Expand Down Expand Up @@ -67,6 +69,7 @@ public String streetSuffix() {
return resolve("address.street_suffix");
}

@Deterministic
public String streetPrefix() {
return resolve("address.street_prefix");
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/net/datafaker/providers/base/Drone.java
@@ -1,5 +1,7 @@
package net.datafaker.providers.base;

import net.datafaker.annotations.Deterministic;

/**
* An unmanned aerial vehicle (UAV), commonly known as a drone, is an aircraft without any human pilot, crew, or passengers on board.
*
Expand Down Expand Up @@ -107,6 +109,7 @@ public String minShutterSpeed() {
return resolve("drone.min_shutter_speed");
}

@Deterministic
public String shutterSpeedUnits() {
return resolve("drone.shutter_speed_units");
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/net/datafaker/providers/base/Locality.java
@@ -1,5 +1,7 @@
package net.datafaker.providers.base;

import net.datafaker.annotations.Deterministic;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
Expand Down Expand Up @@ -42,6 +44,7 @@ public Locality(BaseProviders baseProviders) {
*
* @return a List of Strings with the name of the locale (eg. "es", "es-MX")
*/
@Deterministic
public List<String> allSupportedLocales() {
return allSupportedLocales(Set.of("datafaker"));
}
Expand Down
18 changes: 10 additions & 8 deletions src/main/java/net/datafaker/providers/base/Mbti.java
@@ -1,41 +1,43 @@
package net.datafaker.providers.base;

import java.util.function.Supplier;

/**
* Myers-Briggs Type Indicator
*
* @since 1.5.0
*/
public class Mbti extends AbstractProvider<BaseProviders> {

private final String choice;
private final Supplier<String> choice;

public Mbti(final BaseProviders faker) {
super(faker);
this.choice = this.faker.resolve("mbti.choice");
this.choice = () -> this.faker.resolve("mbti.choice");
}

public String type() {
return resolve("mbti.".concat(choice).concat(".type"));
return resolve("mbti.".concat(choice.get()).concat(".type"));
}

public String name() {
return resolve("mbti.".concat(choice).concat(".name"));
return resolve("mbti.".concat(choice.get()).concat(".name"));
}

public String characteristic() {
return resolve("mbti.".concat(choice).concat(".characteristic"));
return resolve("mbti.".concat(choice.get()).concat(".characteristic"));
}

public String personage() {
return resolve("mbti.".concat(choice).concat(".personage"));
return resolve("mbti.".concat(choice.get()).concat(".personage"));
}

public String merit() {
return resolve("mbti.".concat(choice).concat(".merit"));
return resolve("mbti.".concat(choice.get()).concat(".merit"));
}

public String weakness() {
return resolve("mbti.".concat(choice).concat(".weakness"));
return resolve("mbti.".concat(choice.get()).concat(".weakness"));
}


Expand Down
68 changes: 67 additions & 1 deletion src/test/java/net/datafaker/FakerTest.java
@@ -1,18 +1,31 @@
package net.datafaker;

import net.datafaker.annotations.Deterministic;
import net.datafaker.providers.base.AbstractProvider;
import net.datafaker.providers.base.BaseFaker;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import org.reflections.Reflections;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.reflections.scanners.Scanners.SubTypes;

class FakerTest extends AbstractFakerTest {

Expand Down Expand Up @@ -348,4 +361,57 @@ void shouldNotApplyCachingToMethodsWithParameters() {
String flight2 = faker.expression("#{Aviation.flight 'ICAO'}");
assertThat(flight2).matches("[A-z]{3}\\d{1,4}");
}

@Test
void testDeterministicAndNonDeterministicProvidersReturnValues() {
final Reflections reflections = new Reflections("net.datafaker.providers");
Set<Class<?>> classes = reflections.get(SubTypes.of(AbstractProvider.class).asClass());
for (var clazz: classes) {
Collection<Method> methods = Arrays.stream(clazz.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()) && m.getParameterCount() == 0).collect(Collectors.toSet());
if (methods.isEmpty()) continue;
Constructor<AbstractProvider<?>> constructor = null;
final AbstractProvider<?> ap;
try {
Set<Constructor<AbstractProvider<?>>> constructorsWith1Arg =
Arrays.stream(clazz.getDeclaredConstructors())
.filter(c -> c.getParameterCount() == 1).map(c -> (Constructor<AbstractProvider<?>>) c)
.collect(Collectors.toSet());
for (var c: constructorsWith1Arg) {
Class<?>[] types = c.getParameterTypes();
if (types[0].isAssignableFrom(Faker.class)) {
constructor = c;
break;
}
}
assertThat(constructor).isNotNull();
constructor.setAccessible(true);
ap = constructor.newInstance(faker);
} catch (InvocationTargetException | InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
for (Method m: methods) {
var set = new HashSet<>();
try {
for (int i = 0; i < 10; i++) {
set.add(m.invoke(ap));
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
if (m.isAnnotationPresent(Deterministic.class)) {
assertThat(set)
.as("Class: " + ap.getClass().getName()
+ ", method: " + m.getName() + " should have the same return value")
.hasSize(1);
} else {
assertThat(set)
.as("Class: " + ap.getClass().getName()
+ ", method: " + m.getName() + " should generate different return values")
.hasSizeGreaterThan(1);
}
}
}
}
}
@@ -1,14 +1,7 @@
package net.datafaker.providers.entertainment;

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.util.Strings.isNullOrEmpty;
Expand Down Expand Up @@ -42,28 +35,4 @@ void releaseDate() {
assertThat(oscarMovie.releaseDate()).matches("[A-Za-z,0-9 ]+");
}

/**
* Test for <a href="https://github.com/datafaker-net/datafaker/issues/741">issue741</a>
*/
@ParameterizedTest
@MethodSource("argsProvider")
void issue741(Function<OscarMovie, String> f) {
final OscarMovie oscarMovie = faker.oscarMovie();
assertThat(
faker.stream(() -> f.apply(oscarMovie)).len(10).build()
.<Stream<?>>get().collect(Collectors.toSet()))
.hasSizeGreaterThan(1);
}

static Collection<Function<OscarMovie, String>> argsProvider() {
return List.of(
OscarMovie::actor,
OscarMovie::character,
OscarMovie::getChoice,
OscarMovie::getYear,
OscarMovie::movieName,
OscarMovie::quote,
OscarMovie::releaseDate
);
}
}