[docs] Initial FeatureSet generator documentation (#5188)

* Flatten feature sets for display

* [cli] Add feature set output to config-help

This includes markdown and plain text outputs for config-help.

* [docs] FeatureSet on generator docs
This commit is contained in:
Jim Schubert
2020-02-01 20:51:55 -05:00
committed by GitHub
parent 8d8c106c3a
commit a496c2011f
129 changed files with 13898 additions and 52 deletions

View File

@@ -16,10 +16,12 @@
package org.openapitools.codegen.meta;
import com.google.common.collect.ImmutableList;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.meta.features.annotations.AnnotationType;
import java.util.Arrays;
import java.util.EnumSet;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -178,6 +180,167 @@ public class FeatureSet {
}
}
/**
* Displays a flattened or "normalized" view of the featureSet. This is for simplifying user-facing display only.
*/
public static class FeatureSetFlattened {
String featureCategory;
String featureName;
boolean isSupported;
List<AnnotationType> source = new ArrayList<>(3);
public String getFeatureCategory() {
return featureCategory;
}
public String getFeatureName() {
return featureName;
}
public boolean isSupported() {
return isSupported;
}
public List<AnnotationType> getSource() {
return ImmutableList.copyOf(source);
}
}
public List<FeatureSetFlattened> flatten() {
// TODO: Look at making this method function more generically.
List<FeatureSetFlattened> states = new ArrayList<>();
EnumSet.allOf(ClientModificationFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = ClientModificationFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.clientModificationFeatures.contains(feat);
try {
for (Annotation an : ClientModificationFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(DataTypeFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = DataTypeFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.dataTypeFeatures.contains(feat);
try {
for (Annotation an : DataTypeFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(DocumentationFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = DocumentationFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.documentationFeatures.contains(feat);
try {
for (Annotation an : DocumentationFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(SchemaSupportFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = SchemaSupportFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.schemaSupportFeatures.contains(feat);
try {
for (Annotation an : SchemaSupportFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(GlobalFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = GlobalFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.globalFeatures.contains(feat);
try {
for (Annotation an : GlobalFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(ParameterFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = ParameterFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.parameterFeatures.contains(feat);
try {
for (Annotation an : ParameterFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(SecurityFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = SecurityFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.securityFeatures.contains(feat);
try {
for (Annotation an : SecurityFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
EnumSet.allOf(WireFormatFeature.class).forEach(feat -> {
FeatureSetFlattened state = new FeatureSetFlattened();
state.featureCategory = WireFormatFeature.class.getSimpleName();
state.featureName = feat.name();
state.isSupported = this.wireFormatFeatures.contains(feat);
try {
for (Annotation an : WireFormatFeature.class.getField(feat.name()).getAnnotations()) {
state.source.add(AnnotationType.fromAnnotation(an.annotationType()));
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
states.add(state);
});
return states;
}
/**
* {@code FeatureSet} builder static inner class.
*/

View File

@@ -0,0 +1,12 @@
package org.openapitools.codegen.meta.features.annotations;
public enum AnnotationType {
OAS2, OAS3, ToolingExtension;
public static AnnotationType fromAnnotation(Class<?> input) {
if(input == OAS2.class) return AnnotationType.OAS2;
if(input == OAS3.class) return AnnotationType.OAS3;
if(input == ToolingExtension.class) return AnnotationType.ToolingExtension;
return null;
}
}

View File

@@ -0,0 +1,136 @@
package org.openapitools.codegen.meta;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.meta.features.annotations.AnnotationType;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.testng.Assert.*;
public class FeatureSetTest {
@Test
public void flattOnUnspecified() {
List<FeatureSet.FeatureSetFlattened> flattened = FeatureSet.UNSPECIFIED.flatten();
// There are 73 features at the time of writing this test. This makes sure we get a "Full" flat representation.
int knownFeatureCount = 73;
int checkedCount = 0;
assertTrue(flattened.size() >= knownFeatureCount);
for (FeatureSet.FeatureSetFlattened f : flattened) {
checkedCount += 1;
assertFalse(f.isSupported);
}
assertTrue(checkedCount >= knownFeatureCount);
}
@Test
public void flattenOnMultipleFeatures() {
FeatureSet featureSet = FeatureSet.newBuilder()
.includeClientModificationFeatures(ClientModificationFeature.BasePath)
.includeDataTypeFeatures(DataTypeFeature.Int32, DataTypeFeature.Array)
.includeGlobalFeatures(GlobalFeature.Consumes, GlobalFeature.Examples)
.includeParameterFeatures(ParameterFeature.Body, ParameterFeature.Query)
.includeSecurityFeatures(SecurityFeature.BearerToken, SecurityFeature.BasicAuth, SecurityFeature.OAuth2_Implicit)
.includeDocumentationFeatures(DocumentationFeature.Model)
.includeSchemaSupportFeatures(SchemaSupportFeature.Composite)
.build();
List<FeatureSet.FeatureSetFlattened> flattened = featureSet.flatten();
List<FeatureSet.FeatureSetFlattened> supported = new ArrayList<>();
flattened.forEach(f -> {
if (f.isSupported) {
supported.add(f);
}
});
// note that the order of these checks is deterministic, but unrelated to feature inclusion order in this test.
assertEquals(supported.size(), 12);
Set<AnnotationType> toolingOnly = new HashSet<AnnotationType>() {{
add(AnnotationType.ToolingExtension);
}};
Set<AnnotationType> oas2Only = new HashSet<AnnotationType>() {{
add(AnnotationType.OAS2);
}};
Set<AnnotationType> oas3Only = new HashSet<AnnotationType>() {{
add(AnnotationType.OAS3);
}};
Set<AnnotationType> bothSpecs = new HashSet<AnnotationType>() {{
add(AnnotationType.OAS2);
add(AnnotationType.OAS3);
}};
assertEquals(supported.get(0).featureCategory, ClientModificationFeature.class.getSimpleName());
assertEquals(supported.get(0).featureName, ClientModificationFeature.BasePath.name());
assertEquals(new HashSet<>(supported.get(0).source), toolingOnly);
assertEquals(supported.get(1).featureCategory, DataTypeFeature.class.getSimpleName());
assertEquals(supported.get(1).featureName, DataTypeFeature.Int32.name());
assertEquals(new HashSet<>(supported.get(1).source), bothSpecs);
assertEquals(supported.get(2).featureCategory, DataTypeFeature.class.getSimpleName());
assertEquals(supported.get(2).featureName, DataTypeFeature.Array.name());
assertEquals(new HashSet<>(supported.get(2).source), bothSpecs);
assertEquals(supported.get(3).featureCategory, DocumentationFeature.class.getSimpleName());
assertEquals(supported.get(3).featureName, DocumentationFeature.Model.name());
assertEquals(new HashSet<>(supported.get(3).source), toolingOnly);
assertEquals(supported.get(4).featureCategory, SchemaSupportFeature.class.getSimpleName());
assertEquals(supported.get(4).featureName, SchemaSupportFeature.Composite.name());
assertEquals(new HashSet<>(supported.get(4).source), bothSpecs);
assertEquals(supported.get(5).featureCategory, GlobalFeature.class.getSimpleName());
assertEquals(supported.get(5).featureName, GlobalFeature.Consumes.name());
assertEquals(new HashSet<>(supported.get(5).source), oas2Only);
assertEquals(supported.get(6).featureCategory, GlobalFeature.class.getSimpleName());
assertEquals(supported.get(6).featureName, GlobalFeature.Examples.name());
assertEquals(new HashSet<>(supported.get(6).source), bothSpecs);
assertEquals(supported.get(7).featureCategory, ParameterFeature.class.getSimpleName());
assertEquals(supported.get(7).featureName, ParameterFeature.Query.name());
assertEquals(new HashSet<>(supported.get(7).source), bothSpecs);
assertEquals(supported.get(8).featureCategory, ParameterFeature.class.getSimpleName());
assertEquals(supported.get(8).featureName, ParameterFeature.Body.name());
assertEquals(new HashSet<>(supported.get(8).source), oas2Only);
assertEquals(supported.get(9).featureCategory, SecurityFeature.class.getSimpleName());
assertEquals(supported.get(9).featureName, SecurityFeature.BasicAuth.name());
assertEquals(new HashSet<>(supported.get(9).source), bothSpecs);
assertEquals(supported.get(10).featureCategory, SecurityFeature.class.getSimpleName());
assertEquals(supported.get(10).featureName, SecurityFeature.BearerToken.name());
assertEquals(new HashSet<>(supported.get(10).source), oas3Only);
assertEquals(supported.get(11).featureCategory, SecurityFeature.class.getSimpleName());
assertEquals(supported.get(11).featureName, SecurityFeature.OAuth2_Implicit.name());
assertEquals(new HashSet<>(supported.get(11).source), bothSpecs);
}
@Test
public void flattenOnSingleFeatures() {
FeatureSet featureSet = FeatureSet.newBuilder().includeClientModificationFeatures(ClientModificationFeature.BasePath).build();
List<FeatureSet.FeatureSetFlattened> flattened = featureSet.flatten();
List<FeatureSet.FeatureSetFlattened> supported = new ArrayList<>();
flattened.forEach(f -> {
if (f.isSupported) {
supported.add(f);
}
});
assertEquals(supported.size(), 1);
assertEquals(supported.get(0).featureCategory, ClientModificationFeature.class.getSimpleName());
assertEquals(supported.get(0).featureName, ClientModificationFeature.BasePath.name());
assertEquals(new HashSet<>(supported.get(0).source), new HashSet<AnnotationType>() {{
add(AnnotationType.ToolingExtension);
}});
}
}