diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java index b24019c8d..8251cc79f 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java @@ -80,22 +80,39 @@ public static Map mapResponseProjection(MappingConfig mappingCon * @param document Parent GraphQL document * @return Freemarker data model of the GraphQL type */ - private static Set getFields(MappingConfig mappingConfig, - ExtendedObjectTypeDefinition typeDefinition, - ExtendedDocument document) { - // this includes parameters from base definition and extensions - List typeParameters = FieldDefinitionToParameterMapper.mapFields(mappingConfig, - typeDefinition.getFieldDefinitions(), typeDefinition.getName()); - List typeParametersFromInterfaces = getInterfacesOfType(typeDefinition, document) - .stream() + private static Collection getFields(MappingConfig mappingConfig, + ExtendedObjectTypeDefinition typeDefinition, + ExtendedDocument document) { + // using the map to exclude duplicate fields from the type and interfaces + Map allParameters = new LinkedHashMap<>(); + + // includes parameters from the base definition and extensions + FieldDefinitionToParameterMapper.mapFields(mappingConfig, typeDefinition.getFieldDefinitions(), typeDefinition.getName()) + .forEach(p -> allParameters.put(p.getName(), p)); + // includes parameters from the interface + getInterfacesOfType(typeDefinition, document).stream() .map(i -> FieldDefinitionToParameterMapper.mapFields(mappingConfig, i.getFieldDefinitions(), i.getName())) .flatMap(Collection::stream) - .collect(Collectors.toList()); + .forEach(paramDef -> allParameters.merge(paramDef.getName(), paramDef, TypeDefinitionToDataModelMapper::merge)); + return allParameters.values(); + } - Set allParameters = new LinkedHashSet<>(); - allParameters.addAll(typeParameters); - allParameters.addAll(typeParametersFromInterfaces); - return allParameters; + /** + * Merge parameter definition data from the type and interface + * Annotations from the type have higher precedence + * + * @param typeDef Definition of the same parameter from the type + * @param interfaceDef Definition of the same parameter from the interface + * @return merged parameter definition + */ + private static ParameterDefinition merge(ParameterDefinition typeDef, ParameterDefinition interfaceDef) { + if (Utils.isEmpty(typeDef.getAnnotations())) { + typeDef.setAnnotations(interfaceDef.getAnnotations()); + } + if (Utils.isEmpty(typeDef.getJavaDoc())) { + typeDef.setJavaDoc(interfaceDef.getJavaDoc()); + } + return typeDef; } /** @@ -107,23 +124,23 @@ private static Set getFields(MappingConfig mappingConfig, * @param typeNames Names of all GraphQL types * @return Freemarker data model of the GraphQL type */ - private static Set getProjectionFields(MappingConfig mappingConfig, - ExtendedObjectTypeDefinition typeDefinition, - ExtendedDocument document, - Set typeNames) { - // this includes parameters from base definition and extensions - List typeParameters = FieldDefinitionToParameterMapper.mapProjectionFields( - mappingConfig, typeDefinition.getFieldDefinitions(), typeNames); - List typeParametersFromInterfaces = getInterfacesOfType(typeDefinition, document) - .stream() + private static Collection getProjectionFields(MappingConfig mappingConfig, + ExtendedObjectTypeDefinition typeDefinition, + ExtendedDocument document, + Set typeNames) { + // using the map to exclude duplicate fields from the type and interfaces + Map allParameters = new LinkedHashMap<>(); + + // includes parameters from the base definition and extensions + FieldDefinitionToParameterMapper.mapProjectionFields(mappingConfig, typeDefinition.getFieldDefinitions(), typeNames) + .forEach(p -> allParameters.put(p.getName(), p)); + // includes parameters from the interface + getInterfacesOfType(typeDefinition, document).stream() .map(i -> FieldDefinitionToParameterMapper.mapProjectionFields(mappingConfig, i.getFieldDefinitions(), typeNames)) .flatMap(Collection::stream) - .collect(Collectors.toList()); - - Set allParameters = new LinkedHashSet<>(); - allParameters.addAll(typeParameters); - allParameters.addAll(typeParametersFromInterfaces); - return allParameters; + .filter(paramDef -> !allParameters.containsKey(paramDef.getName())) + .forEach(paramDef -> allParameters.put(paramDef.getName(), paramDef)); + return allParameters.values(); } /** diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenDefaultsTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenDefaultsTest.java index fa9c3b02e..61ad4d8f2 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenDefaultsTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenDefaultsTest.java @@ -1,19 +1,18 @@ package com.kobylynskyi.graphql.codegen; +import com.kobylynskyi.graphql.codegen.model.MappingConfig; +import com.kobylynskyi.graphql.codegen.utils.Utils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import java.io.File; -import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import com.kobylynskyi.graphql.codegen.model.MappingConfig; -import com.kobylynskyi.graphql.codegen.utils.Utils; - +import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -21,8 +20,8 @@ class GraphQLCodegenDefaultsTest { private GraphQLCodegen generator; - private File outputBuildDir = new File("build/generated"); - private File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/testdefaults"); + private final File outputBuildDir = new File("build/generated"); + private final File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/testdefaults"); @BeforeEach void init() { @@ -33,7 +32,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } @@ -46,8 +45,8 @@ void generate_CheckFiles() throws Exception { assertEquals(Arrays.asList("InputWithDefaults.java", "MyEnum.java", "SomeObject.java"), generatedFileNames); for (File file : files) { - File expected = new File(String.format("src/test/resources/expected-classes/%s.txt", file.getName())); - TestUtils.assertSameTrimmedContent(expected, file); + assertSameTrimmedContent(new File(String.format("src/test/resources/expected-classes/%s.txt", file.getName())), + file); } } } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExtendTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExtendTest.java index 6fe6c9415..0843d8b3d 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExtendTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExtendTest.java @@ -8,12 +8,14 @@ import org.junit.jupiter.api.Test; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.nio.file.Paths; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; +import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toSet; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -31,7 +33,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } @@ -104,19 +106,13 @@ void generateClientSideClasses() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File eventResponseProjectionFile = Arrays.stream(files) - .filter(file -> file.getName().equalsIgnoreCase("EventResponseProjection.java")).findFirst() - .orElseThrow(FileNotFoundException::new); assertSameTrimmedContent( new File("src/test/resources/expected-classes/extend/request/EventResponseProjection.java.txt"), - eventResponseProjectionFile); + getFileByName(files, "EventResponseProjection.java")); - File assetResponseProjectionFile = Arrays.stream(files) - .filter(file -> file.getName().equalsIgnoreCase("AssetResponseProjection.java")).findFirst() - .orElseThrow(FileNotFoundException::new); assertSameTrimmedContent( new File("src/test/resources/expected-classes/extend/request/AssetResponseProjection.java.txt"), - assetResponseProjectionFile); + getFileByName(files, "AssetResponseProjection.java")); } @Test diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExternalConfigTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExternalConfigTest.java index 75463da6b..42c96ac69 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExternalConfigTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenExternalConfigTest.java @@ -16,11 +16,9 @@ class GraphQLCodegenExternalConfigTest { /** * Check mapping config from json file. - * - * @throws Exception the exception */ @Test - void check_mappingConfigFromJsonFile() throws Exception { + void check_mappingConfigFromJsonFile() { MappingConfig externalMappingConfig = new JsonMappingConfigSupplier("src/test/resources/json/mappingconfig.json").get(); assertEquals(externalMappingConfig.getPackageName(), "com.kobylynskyi.graphql.testconfigjson"); @@ -32,11 +30,9 @@ void check_mappingConfigFromJsonFile() throws Exception { /** * Check combine mapping config with external. - * - * @throws Exception the exception */ @Test - void check_combineMappingConfigWithExternal() throws Exception { + void check_combineMappingConfigWithExternal() { MappingConfig mappingConfig = new MappingConfig(); mappingConfig.setPackageName("com.kobylynskyi.graphql.test1"); diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsResolversTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsResolversTest.java index e0ddbad6e..68aff359d 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsResolversTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsResolversTest.java @@ -8,7 +8,6 @@ import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -33,7 +32,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenGitHubTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenGitHubTest.java index 72fc4c8b8..8e32f3aba 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenGitHubTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenGitHubTest.java @@ -8,13 +8,12 @@ import org.junit.jupiter.api.Test; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import java.util.Objects; import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; +import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; import static org.hamcrest.MatcherAssert.assertThat; class GraphQLCodegenGitHubTest { @@ -34,7 +33,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } @@ -43,11 +42,12 @@ void generate_MultipleInterfacesPerType() throws Exception { generator.generate(); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File commitFile = getGeneratedFile(files, "Commit.java"); - assertSameTrimmedContent(new File("src/test/resources/expected-classes/Commit.java.txt"), commitFile); - File profileOwner = getGeneratedFile(files, "ProfileOwner.java"); - assertSameTrimmedContent(new File("src/test/resources/expected-classes/ProfileOwner.java.txt"), profileOwner); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/Commit.java.txt"), + getFileByName(files, "Commit.java")); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/ProfileOwner.java.txt"), + getFileByName(files, "ProfileOwner.java")); } @Test @@ -60,25 +60,25 @@ void generate_ClassNameWithSuffix_Prefix() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); // verify proper class name for GraphQL interface - assertThat(getGeneratedFileContent(files, "GithubActorTO.java"), + assertThat(getFileContent(files, "GithubActorTO.java"), StringContains.containsString("public interface GithubActorTO ")); // verify proper class name for GraphQL enum - assertThat(getGeneratedFileContent(files, "GithubIssueStateTO.java"), + assertThat(getFileContent(files, "GithubIssueStateTO.java"), StringContains.containsString("public enum GithubIssueStateTO ")); // verify proper class name for GraphQL union - assertThat(getGeneratedFileContent(files, "GithubAssigneeTO.java"), + assertThat(getFileContent(files, "GithubAssigneeTO.java"), StringContains.containsString("public interface GithubAssigneeTO ")); // verify proper class name for GraphQL input assertSameTrimmedContent( new File("src/test/resources/expected-classes/GithubAcceptTopicSuggestionInputTO.java.txt"), - getGeneratedFile(files, "GithubAcceptTopicSuggestionInputTO.java")); + getFileByName(files, "GithubAcceptTopicSuggestionInputTO.java")); // verify proper class name for GraphQL type and references to interfaces/types/unions for GraphQL type assertSameTrimmedContent(new File("src/test/resources/expected-classes/GithubCommitTO.java.txt"), - getGeneratedFile(files, "GithubCommitTO.java")); + getFileByName(files, "GithubCommitTO.java")); } @Test @@ -86,20 +86,13 @@ void generate_NoValidationAnnotation() throws Exception { mappingConfig.setModelValidationAnnotation(null); generator.generate(); - File commitFile = getGeneratedFile(Objects.requireNonNull(outputJavaClassesDir.listFiles()), "Commit.java"); + File commitFile = getFileByName(Objects.requireNonNull(outputJavaClassesDir.listFiles()), "Commit.java"); assertSameTrimmedContent(new File("src/test/resources/expected-classes/Commit_noValidationAnnotation.java.txt"), commitFile); } - private static String getGeneratedFileContent(File[] files, String fileName) throws IOException { - File file = getGeneratedFile(files, fileName); - return Utils.getFileContent(file.getPath()); + private static String getFileContent(File[] files, String fileName) throws IOException { + return Utils.getFileContent(getFileByName(files, fileName).getPath()); } - private static File getGeneratedFile(File[] files, String fileName) throws FileNotFoundException { - return Arrays.stream(files) - .filter(f -> f.getName().equalsIgnoreCase(fileName)) - .findFirst() - .orElseThrow(FileNotFoundException::new); - } } \ No newline at end of file diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenMultiFilesTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenMultiFilesTest.java index 90212f945..f2d2b0ce6 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenMultiFilesTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenMultiFilesTest.java @@ -1,27 +1,26 @@ package com.kobylynskyi.graphql.codegen; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - +import com.kobylynskyi.graphql.codegen.model.MappingConfig; +import com.kobylynskyi.graphql.codegen.utils.Utils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.kobylynskyi.graphql.codegen.model.MappingConfig; -import com.kobylynskyi.graphql.codegen.utils.Utils; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; class GraphQLCodegenMultiFilesTest { - private GraphQLCodegen generator; + private final File outputBuildDir = new File("build/generated"); + private final File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/multifiles"); - private File outputBuildDir = new File("build/generated"); - private File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/multifiles"); + private GraphQLCodegen generator; @BeforeEach void init() { @@ -35,7 +34,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } @@ -48,8 +47,9 @@ void generate_CheckFiles() throws Exception { assertEquals(Arrays.asList("MyUnion.java", "UnionMember1.java", "UnionMember2.java"), generatedFileNames); for (File file : files) { - File expected = new File(String.format("src/test/resources/expected-classes/%s.txt", file.getName())); - TestUtils.assertSameTrimmedContent(expected, file); + assertSameTrimmedContent( + new File(String.format("src/test/resources/expected-classes/%s.txt", file.getName())), + file); } } } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenRequestTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenRequestTest.java index 2044dba67..4918cf108 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenRequestTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenRequestTest.java @@ -7,12 +7,10 @@ import org.junit.jupiter.api.Test; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Arrays; import java.util.Objects; import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; +import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -34,7 +32,7 @@ void init() { } @AfterEach - void cleanup() throws IOException { + void cleanup() { Utils.deleteDir(new File("build/generated")); } @@ -46,15 +44,15 @@ void generate_RequestAndResponseProjections() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventResponseProjection.java.txt"), - getGeneratedFile(files, "EventResponseProjection.java")); + getFileByName(files, "EventResponseProjection.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventPropertyResponseProjection.java.txt"), - getGeneratedFile(files, "EventPropertyResponseProjection.java")); + getFileByName(files, "EventPropertyResponseProjection.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventsByCategoryAndStatusQueryRequest.java.txt"), - getGeneratedFile(files, "EventsByCategoryAndStatusQueryRequest.java")); + getFileByName(files, "EventsByCategoryAndStatusQueryRequest.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/VersionQueryRequest.java.txt"), - getGeneratedFile(files, "VersionQueryRequest.java")); + getFileByName(files, "VersionQueryRequest.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventsByIdsQueryRequest.java.txt"), - getGeneratedFile(files, "EventsByIdsQueryRequest.java")); + getFileByName(files, "EventsByIdsQueryRequest.java")); } @Test @@ -66,9 +64,9 @@ void generate_WithModelSuffix() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventStatusTO.java.txt"), - getGeneratedFile(files, "EventStatusTO.java")); + getFileByName(files, "EventStatusTO.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventsByCategoryAndStatusQueryRequest_withModelSuffix.java.txt"), - getGeneratedFile(files, "EventsByCategoryAndStatusQueryRequest.java")); + getFileByName(files, "EventsByCategoryAndStatusQueryRequest.java")); } @Test @@ -79,10 +77,10 @@ void generate_RequestAndResponseProjections_github() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/CodeOfConductResponseProjection.java.txt"), - getGeneratedFile(files, "CodeOfConductResponseProjection.java")); + getFileByName(files, "CodeOfConductResponseProjection.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/UpdateRepositoryMutationRequest.java.txt"), - getGeneratedFile(files, "UpdateRepositoryMutationRequest.java")); + getFileByName(files, "UpdateRepositoryMutationRequest.java")); } @Test @@ -93,7 +91,7 @@ void generate_ToStringIsEnabledForInput() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/AcceptTopicSuggestionInput.java.txt"), - getGeneratedFile(files, "AcceptTopicSuggestionInput.java")); + getFileByName(files, "AcceptTopicSuggestionInput.java")); } @Test @@ -104,7 +102,7 @@ void generate_emptyRequestSuffix() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - assertNotNull(getGeneratedFile(files, "EventsByCategoryAndStatusQuery.java")); + assertNotNull(getFileByName(files, "EventsByCategoryAndStatusQuery.java")); } @Test @@ -116,7 +114,7 @@ void generate_noApiImportForModelClasses() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - assertNotNull(getGeneratedFile(files, "EventsByCategoryAndStatusQueryRequest.java")); + assertNotNull(getFileByName(files, "EventsByCategoryAndStatusQueryRequest.java")); } @Test @@ -130,7 +128,7 @@ void generate_apiImportForModelClassesIfResolverIsPresent() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventsByCategoryAndStatusQueryRequest_withApiImport.java.txt"), - getGeneratedFile(files, "EventsByCategoryAndStatusQueryRequest.java")); + getFileByName(files, "EventsByCategoryAndStatusQueryRequest.java")); } @Test @@ -144,7 +142,7 @@ void generate_apiImportForModelClassesIfResolversExtensions() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/EventsByCategoryAndStatusQueryRequest_withApiImport.java.txt"), - getGeneratedFile(files, "EventsByCategoryAndStatusQueryRequest.java")); + getFileByName(files, "EventsByCategoryAndStatusQueryRequest.java")); } @Test @@ -155,16 +153,10 @@ void generate_QueriesWithSameName() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/ProductsByCategoryIdAndStatusQueryRequest.java.txt"), - getGeneratedFile(files, "ProductsByCategoryIdAndStatusQueryRequest.java")); + getFileByName(files, "ProductsByCategoryIdAndStatusQueryRequest.java")); assertSameTrimmedContent(new File("src/test/resources/expected-classes/request/ProductsByIdsQueryRequest.java.txt"), - getGeneratedFile(files, "ProductsByIdsQueryRequest.java")); + getFileByName(files, "ProductsByIdsQueryRequest.java")); } - private static File getGeneratedFile(File[] files, String fileName) throws FileNotFoundException { - return Arrays.stream(files) - .filter(f -> f.getName().equalsIgnoreCase(fileName)) - .findFirst() - .orElseThrow(FileNotFoundException::new); - } } \ No newline at end of file diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenTest.java index 99960aaf7..2938fc9d1 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenTest.java @@ -11,12 +11,12 @@ import org.junit.jupiter.api.Test; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.NoSuchFileException; import java.util.*; import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent; +import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.toList; @@ -25,12 +25,12 @@ class GraphQLCodegenTest { + private final File outputBuildDir = new File("build/generated"); + private final File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/test1"); + private MappingConfig mappingConfig; private GraphQLCodegen generator; - private File outputBuildDir = new File("build/generated"); - private File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/test1"); - @BeforeEach void init() { mappingConfig = new MappingConfig(); @@ -78,9 +78,9 @@ void generate_NoBuilder() throws Exception { outputBuildDir, mappingConfig).generate(); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertSameTrimmedContent(new File("src/test/resources/expected-classes/Event_noBuilder.java.txt"), eventFile); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/Event_noBuilder.java.txt"), + getFileByName(files, "Event.java")); } @Test @@ -90,11 +90,8 @@ void generate_CustomMappings() throws Exception { generator.generate(); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), - StringContains.containsString("java.util.Date createdDateTime;")); + assertFileContainsElements(files, "Event.java", "java.util.Date createdDateTime;"); } @Test @@ -106,92 +103,70 @@ void generate_CustomMappings_Nested() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); // As per mapping, only EventProperty.intVal should be mapped to java.math.BigInteger - File eventPropertyFile = Arrays.stream(files) - .filter(file -> file.getName().equalsIgnoreCase("EventProperty.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventPropertyFile.getPath()), - StringContains.containsString("private java.math.BigInteger intVal;")); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString("private Integer rating;")); + assertFileContainsElements(files, "EventProperty.java", "private java.math.BigInteger intVal;"); + assertFileContainsElements(files, "Event.java", "private Integer rating;"); } @Test void generate_NoCustomMappings() throws Exception { mappingConfig.setModelNameSuffix(" "); + generator.generate(); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString("String createdDateTime;")); + assertFileContainsElements(files, "Event.java", "String createdDateTime;"); } @Test void generate_NullCustomMappings() throws Exception { mappingConfig.setCustomTypesMapping(null); + generator.generate(); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString("String createdDateTime;")); + assertFileContainsElements(files, "Event.java", "String createdDateTime;"); } @Test void generate_CustomAnnotationMappings() throws Exception { - mappingConfig.setCustomTypesMapping( - new HashMap<>(singletonMap("Event.createdDateTime", "org.joda.time.DateTime"))); - + mappingConfig.setCustomTypesMapping(new HashMap<>(singletonMap("Event.createdDateTime", "org.joda.time.DateTime"))); mappingConfig.setCustomAnnotationsMapping(new HashMap<>(singletonMap("Event.createdDateTime", "com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)"))); generator.generate(); - File eventFile = Arrays.stream(Objects.requireNonNull(outputJavaClassesDir.listFiles())) - .filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString( + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + assertFileContainsElements(files, "Event.java", "@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)" - + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;")); + + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;"); } @Test void generate_CustomAnnotationMappings_Type() throws Exception { - mappingConfig.setCustomTypesMapping( - new HashMap<>(singletonMap("DateTime", "org.joda.time.DateTime"))); - + mappingConfig.setCustomTypesMapping(new HashMap<>(singletonMap("DateTime", "org.joda.time.DateTime"))); mappingConfig.setCustomAnnotationsMapping(new HashMap<>(singletonMap("DateTime", "com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)"))); generator.generate(); - File eventFile = Arrays.stream(Objects.requireNonNull(outputJavaClassesDir.listFiles())) - .filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString( + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + assertFileContainsElements(files, "Event.java", "@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)" - + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;")); + + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;"); } @Test void generate_CustomAnnotationMappings_FieldType() throws Exception { - mappingConfig - .setCustomTypesMapping(new HashMap<>(singletonMap("DateTime", "org.joda.time.DateTime"))); - + mappingConfig.setCustomTypesMapping(new HashMap<>(singletonMap("DateTime", "org.joda.time.DateTime"))); mappingConfig.setCustomAnnotationsMapping(new HashMap<>(singletonMap("Event.createdDateTime", "com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)"))); generator.generate(); - File eventFile = Arrays.stream(Objects.requireNonNull(outputJavaClassesDir.listFiles())) - .filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString( + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + assertFileContainsElements(files, "Event.java", "@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)" - + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;")); + + System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;"); } @Test @@ -200,11 +175,10 @@ void generate_CustomSubscriptionReturnType() throws Exception { generator.generate(); - File eventFile = Arrays.stream(Objects.requireNonNull(outputJavaClassesDir.listFiles())) - .filter(file -> file.getName().equalsIgnoreCase("EventsCreatedSubscription.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString( - "org.reactivestreams.Publisher> eventsCreated() throws Exception;")); + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + + assertFileContainsElements(files, "EventsCreatedSubscription.java", + "org.reactivestreams.Publisher> eventsCreated() throws Exception;"); } @Test @@ -213,15 +187,12 @@ void generate_NoPackage() throws Exception { generator.generate(); File[] files = Objects.requireNonNull(outputBuildDir.listFiles()); - File eventFile = Arrays.stream(files).filter(file -> file.getName().equalsIgnoreCase("Event.java")).findFirst() - .orElseThrow(FileNotFoundException::new); - - assertThat(Utils.getFileContent(eventFile.getPath()), StringStartsWith.startsWith( - System.lineSeparator() + - "/**" + System.lineSeparator() + - " * An event that describes a thing that happens" + System.lineSeparator() + - " */" + System.lineSeparator() + - "public class Event {")); + + assertFileContainsElements(files, "Event.java", System.lineSeparator() + + "/**" + System.lineSeparator() + + " * An event that describes a thing that happens" + System.lineSeparator() + + " */" + System.lineSeparator() + + "public class Event {"); } @Test @@ -235,26 +206,20 @@ void generate_CustomModelAndApiPackages() throws Exception { assertEquals(Arrays.asList("CreateEventMutation.java", "EventByIdQuery.java", "EventsByCategoryAndStatusQuery.java", "EventsByIdsQuery.java", "EventsCreatedSubscription.java", "Mutation.java", "Query.java", "Subscription.java", "VersionQuery.java"), generatedApiFileNames); - Arrays.stream(apiFiles).forEach(file -> { - try { - assertThat(Utils.getFileContent(file.getPath()), - StringStartsWith.startsWith("package com.kobylynskyi.graphql.test1.api;")); - } catch (IOException e) { - fail(e); - } - }); + + for (File apiFile : apiFiles) { + assertThat(Utils.getFileContent(apiFile.getPath()), + StringStartsWith.startsWith("package com.kobylynskyi.graphql.test1.api;")); + } File[] modelFiles = Objects.requireNonNull(new File(outputJavaClassesDir, "model").listFiles()); List generatedModelFileNames = Arrays.stream(modelFiles).map(File::getName).sorted().collect(toList()); assertEquals(Arrays.asList("Event.java", "EventProperty.java", "EventStatus.java"), generatedModelFileNames); - Arrays.stream(modelFiles).forEach(file -> { - try { - assertThat(Utils.getFileContent(file.getPath()), - StringStartsWith.startsWith("package com.kobylynskyi.graphql.test1.model;")); - } catch (IOException e) { - fail(e); - } - }); + + for (File modelFile : modelFiles) { + assertThat(Utils.getFileContent(modelFile.getPath()), + StringStartsWith.startsWith("package com.kobylynskyi.graphql.test1.model;")); + } } @Test @@ -281,11 +246,8 @@ void generate_EqualsAndHashCode() throws Exception { } } - assertEquals(Utils.getFileContent( - "src/test/resources/expected-classes/EventPropertyTO_withEqualsAndHashCode.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("EventPropertyTO.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/EventPropertyTO_withEqualsAndHashCode.java.txt"), + getFileByName(files, "EventPropertyTO.java")); } @Test @@ -309,10 +271,8 @@ void generate_toString() throws Exception { assertThat(content, StringContains.containsString("public String toString()")); } } - assertEquals(Utils.getFileContent("src/test/resources/expected-classes/EventPropertyTO_toString.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("EventPropertyTO.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/EventPropertyTO_toString.java.txt"), + getFileByName(files, "EventPropertyTO.java")); } @Test @@ -339,14 +299,10 @@ void generate_NoQueries() throws Exception { File[] files = Objects.requireNonNull(outputBuildDir.listFiles()); assertEquals(2, files.length); - assertEquals(Utils.getFileContent("src/test/resources/expected-classes/EmptyMutation.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("Mutation.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); - assertEquals(Utils.getFileContent("src/test/resources/expected-classes/EmptyQuery.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("Query.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/EmptyMutation.java.txt"), + getFileByName(files, "Mutation.java")); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/EmptyQuery.java.txt"), + getFileByName(files, "Query.java")); } @Test @@ -392,7 +348,6 @@ void generate_AsyncQueryApis() throws Exception { assertFileContainsElements(files, "EventByIdQuery.java", "java.util.concurrent.CompletableFuture eventById("); - } @Test @@ -404,7 +359,6 @@ void generate_AsyncMutationApis() throws Exception { assertFileContainsElements(files, "CreateEventMutation.java", "java.util.concurrent.CompletableFuture createEvent("); - } @Test @@ -418,7 +372,7 @@ void generate_deprecated() throws Exception { "Mutation.java", "Node.java", "PinnableItem.java", "Query.java", "Status.java"), generatedFileNames); for (File file : files) { - TestUtils.assertSameTrimmedContent( + assertSameTrimmedContent( new File(String.format("src/test/resources/expected-classes/deprecated/%s.txt", file.getName())), file); } @@ -431,28 +385,40 @@ void generate_QueriesWithSameName() throws Exception { File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - assertEquals(Utils.getFileContent("src/test/resources/expected-classes/ProductsByCategoryIdAndStatusQuery.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("ProductsByCategoryIdAndStatusQuery.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); - assertEquals(Utils.getFileContent("src/test/resources/expected-classes/ProductsByIdsQuery.java.txt"), - Utils.getFileContent( - Arrays.stream(files).filter(f -> f.getName().equals("ProductsByIdsQuery.java")).map(File::getPath) - .findFirst().orElseThrow(FileNotFoundException::new))); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/ProductsByCategoryIdAndStatusQuery.java.txt"), + getFileByName(files, "ProductsByCategoryIdAndStatusQuery.java")); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/ProductsByIdsQuery.java.txt"), + getFileByName(files, "ProductsByIdsQuery.java")); } - private void assertFileContainsElements(File[] files, String fileName, String... elements) - throws IOException { - File file = getFile(files, fileName); + @Test + void generate_InterfaceAndTypeHavingDuplicateFields() throws Exception { + new GraphQLCodegen(singletonList("src/test/resources/schemas/type-interface-duplicate-fields.graphqls"), + outputBuildDir, mappingConfig).generate(); - assertNotNull(file); + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); - String fileContent = Utils.getFileContent(file.getPath()); - assertThat(fileContent, Matchers.stringContainsInOrder(elements)); + assertSameTrimmedContent(new File("src/test/resources/expected-classes/Person.java.txt"), + getFileByName(files, "Person.java")); } - private File getFile(File[] files, String fileName) { - return Arrays.stream(files).filter(f -> f.getName().equals(fileName)).findFirst().get(); + @Test + void generate_InterfaceAndTypeHavingDuplicateFields1() throws Exception { + new GraphQLCodegen(singletonList("src/test/resources/schemas/type-interface-duplicate-fields1.graphqls"), + outputBuildDir, mappingConfig).generate(); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + + assertSameTrimmedContent(new File("src/test/resources/expected-classes/Person1.java.txt"), + getFileByName(files, "Person.java")); + } + + private void assertFileContainsElements(File[] files, String fileName, String... elements) + throws IOException { + File file = getFileByName(files, fileName); + String fileContent = Utils.getFileContent(file.getPath()); + assertThat(fileContent, Matchers.stringContainsInOrder(elements)); } } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/TestUtils.java b/src/test/java/com/kobylynskyi/graphql/codegen/TestUtils.java index 0e610ffb3..39d7e632e 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/TestUtils.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/TestUtils.java @@ -1,14 +1,23 @@ package com.kobylynskyi.graphql.codegen; +import com.kobylynskyi.graphql.codegen.utils.Utils; + import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; - -import com.kobylynskyi.graphql.codegen.utils.Utils; +import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertEquals; public class TestUtils { + public static File getFileByName(File[] files, String fileName) throws FileNotFoundException { + return Arrays.stream(files) + .filter(f -> f.getName().equalsIgnoreCase(fileName)) + .findFirst() + .orElseThrow(FileNotFoundException::new); + } + public static void assertSameTrimmedContent(File expected, File file) throws IOException { String expectedContent = Utils.getFileContent(expected.getPath()).trim(); String actualContent = Utils.getFileContent(file.getPath()).trim(); diff --git a/src/test/resources/expected-classes/Person.java.txt b/src/test/resources/expected-classes/Person.java.txt new file mode 100644 index 000000000..0904b0628 --- /dev/null +++ b/src/test/resources/expected-classes/Person.java.txt @@ -0,0 +1,75 @@ +package com.kobylynskyi.graphql.test1; + + +public class Person implements NamedEntity{ + + private String name; + private Integer age; + + public Person() { + } + + public Person(String name, Integer age) { + this.name = name; + this.age = age; + } + + /** + * an awesome name! + */ + public String getName() { + return name; + } + /** + * an awesome name! + */ + public void setName(String name) { + this.name = name; + } + + /** + * age in years + */ + public Integer getAge() { + return age; + } + /** + * age in years + */ + public void setAge(Integer age) { + this.age = age; + } + + + + public static class Builder { + + private String name; + private Integer age; + + public Builder() { + } + + /** + * an awesome name! + */ + public Builder setName(String name) { + this.name = name; + return this; + } + + /** + * age in years + */ + public Builder setAge(Integer age) { + this.age = age; + return this; + } + + + public Person build() { + return new Person(name, age); + } + + } +} diff --git a/src/test/resources/expected-classes/Person1.java.txt b/src/test/resources/expected-classes/Person1.java.txt new file mode 100644 index 000000000..168328cb5 --- /dev/null +++ b/src/test/resources/expected-classes/Person1.java.txt @@ -0,0 +1,79 @@ +package com.kobylynskyi.graphql.test1; + + +public class Person implements NamedEntity{ + + @Deprecated + private String name; + private Integer age; + + public Person() { + } + + public Person(String name, Integer age) { + this.name = name; + this.age = age; + } + + /** + * an awesome name! + */ + @Deprecated + public String getName() { + return name; + } + /** + * an awesome name! + */ + @Deprecated + public void setName(String name) { + this.name = name; + } + + /** + * age in years + */ + public Integer getAge() { + return age; + } + /** + * age in years + */ + public void setAge(Integer age) { + this.age = age; + } + + + + public static class Builder { + + private String name; + private Integer age; + + public Builder() { + } + + /** + * an awesome name! + */ + @Deprecated + public Builder setName(String name) { + this.name = name; + return this; + } + + /** + * age in years + */ + public Builder setAge(Integer age) { + this.age = age; + return this; + } + + + public Person build() { + return new Person(name, age); + } + + } +} \ No newline at end of file diff --git a/src/test/resources/schemas/type-interface-duplicate-fields.graphqls b/src/test/resources/schemas/type-interface-duplicate-fields.graphqls new file mode 100644 index 000000000..4925e1f4d --- /dev/null +++ b/src/test/resources/schemas/type-interface-duplicate-fields.graphqls @@ -0,0 +1,11 @@ +interface NamedEntity { + # an awesome name! + name: String @deprecated +} + +type Person implements NamedEntity { + name: String + + # age in years + age: Int +} \ No newline at end of file diff --git a/src/test/resources/schemas/type-interface-duplicate-fields1.graphqls b/src/test/resources/schemas/type-interface-duplicate-fields1.graphqls new file mode 100644 index 000000000..dae7002a5 --- /dev/null +++ b/src/test/resources/schemas/type-interface-duplicate-fields1.graphqls @@ -0,0 +1,11 @@ +interface NamedEntity { + name: String @shouldnotbehere +} + +type Person implements NamedEntity { + # an awesome name! + name: String @deprecated + + # age in years + age: Int +} \ No newline at end of file