Skip to content

Commit

Permalink
[BUG] [C++][Pistache] cpp-pistache-server generating API include unde… (
Browse files Browse the repository at this point in the history
#18553)

* [BUG] [C++][Pistache] cpp-pistache-server generating API include undefined "Object.h" (#2769)

Should handle Object.h, AnyType.h correctly. Set.h also tested.

   - #include Object.h removed and replaced by a typeMapping.put(object, nlohmann::json) like suggested in other issues
   - object had an invalid syntax: ':' instead of '::' in types with namespace
   - extra include of #include nlohmann/json.h removed when there's already #include <nlohmann/json.hpp>
   - nlohmann::json is excluded from model namespace

Tested with custom petstore played, with suggested openapi specs coming from issues #2769, #10266, #14234

   ```bash
   rm -rf samples/server/petstore/cpp-pistache-everything/ && ./bin/generate-samples.sh ./bin/configs/cpp-pistache-server-cpp-pistache-everything.yaml  && cd samples/server/petstore/cpp-pistache-everything/ && mkdir build && cd build && cmake .. && cmake --build . --parallel
   ```

* - Adding to samples/server/petstore cpp-pistache-everything

* - .md and FILES missing
  • Loading branch information
mlebihan authored May 4, 2024
1 parent d3b156d commit fde8c77
Show file tree
Hide file tree
Showing 43 changed files with 5,331 additions and 33 deletions.
7 changes: 7 additions & 0 deletions bin/configs/cpp-pistache-server-cpp-pistache-everything.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
generatorName: cpp-pistache-server
outputDir: samples/server/petstore/cpp-pistache-everything
inputSpec: modules/openapi-generator/src/test/resources/3_0/issues-anytype-object-set-petstore-everything.yaml
templateDir: modules/openapi-generator/src/main/resources/cpp-pistache-server
additionalProperties:
useStructModel: "false"
addExternalLibs: "true"
1 change: 0 additions & 1 deletion docs/generators/cpp-pistache-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl

| Type/Alias | Imports |
| ---------- | ------- |
|Object|#include &quot;Object.h&quot;|
|nlohmann::json|#include &lt;nlohmann/json.hpp&gt;|
|std::map|#include &lt;map&gt;|
|std::string|#include &lt;string&gt;|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package org.openapitools.codegen.languages;

import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.servers.Server;
Expand Down Expand Up @@ -53,6 +52,27 @@ public class CppPistacheServerCodegen extends AbstractCppCodegen {
protected final String PREFIX = "";
protected String helpersPackage = "";

/** OpenApi types that shouldn't have a namespace added with getTypeDeclaration() at generation time (for nlohmann::json) */
private final Set<String> openAPITypesWithoutModelNamespace = new HashSet<>();

/** int32_t (for integer) */
private static final String INT32_T = "int32_t";

/** int64_t (for long) */
private static final String INT64_T = "int64_t";

/** nlohmann::json (for object, AnyType) */
private static final String NLOHMANN_JSON = "nlohmann::json";

/** std:string (for date, DateTime, string, file, binary, UUID, URI, ByteArray) */
private static final String STD_STRING = "std::string";

/** std:map (for map) */
private static final String STD_MAP = "std::map";

/** std:vector (for array, set) */
private static final String STD_VECTOR = "std::vector";

@Override
public CodegenType getTag() {
return CodegenType.SERVER;
Expand Down Expand Up @@ -117,33 +137,35 @@ public CppPistacheServerCodegen() {
setupSupportingFiles();

languageSpecificPrimitives = new HashSet<>(
Arrays.asList("int", "char", "bool", "long", "float", "double", "int32_t", "int64_t"));
Arrays.asList("int", "char", "bool", "long", "float", "double", INT32_T, INT64_T));

typeMapping = new HashMap<>();
typeMapping.put("date", "std::string");
typeMapping.put("DateTime", "std::string");
typeMapping.put("string", "std::string");
typeMapping.put("integer", "int32_t");
typeMapping.put("long", "int64_t");
typeMapping.put("date", STD_STRING);
typeMapping.put("DateTime", STD_STRING);
typeMapping.put("string", STD_STRING);
typeMapping.put("integer", INT32_T);
typeMapping.put("long", INT64_T);
typeMapping.put("boolean", "bool");
typeMapping.put("array", "std::vector");
typeMapping.put("map", "std::map");
typeMapping.put("set", "std::vector");
typeMapping.put("file", "std::string");
typeMapping.put("object", "Object");
typeMapping.put("binary", "std::string");
typeMapping.put("array", STD_VECTOR);
typeMapping.put("map", STD_MAP);
typeMapping.put("set", STD_VECTOR);
typeMapping.put("file", STD_STRING);
typeMapping.put("object", NLOHMANN_JSON);
typeMapping.put("binary", STD_STRING);
typeMapping.put("number", "double");
typeMapping.put("UUID", "std::string");
typeMapping.put("URI", "std::string");
typeMapping.put("ByteArray", "std::string");
typeMapping.put("AnyType", "nlohmann::json");
typeMapping.put("UUID", STD_STRING);
typeMapping.put("URI", STD_STRING);
typeMapping.put("ByteArray", STD_STRING);
typeMapping.put("AnyType", NLOHMANN_JSON);

super.importMapping = new HashMap<>();
importMapping.put("std::vector", "#include <vector>");
importMapping.put("std::map", "#include <map>");
importMapping.put("std::string", "#include <string>");
importMapping.put("Object", "#include \"Object.h\"");
importMapping.put("nlohmann::json", "#include <nlohmann/json.hpp>");
importMapping.put(STD_VECTOR, "#include <vector>");
importMapping.put(STD_MAP, "#include <map>");
importMapping.put(STD_STRING, "#include <string>");
importMapping.put(NLOHMANN_JSON, "#include <nlohmann/json.hpp>");

// nlohmann:json doesn't belong to model package
this.openAPITypesWithoutModelNamespace.add(NLOHMANN_JSON);
}

private void setupSupportingFiles() {
Expand Down Expand Up @@ -202,8 +224,16 @@ private void setupModelTemplate() {
}
}

/**
* {@inheritDoc}
*/
@Override
public String toModelImport(String name) {
// Do not reattempt to add #include on an already solved #include
if (name.startsWith("#include")) {
return null;
}

if (importMapping.containsKey(name)) {
return importMapping.get(name);
} else {
Expand All @@ -214,20 +244,23 @@ public String toModelImport(String name) {

@Override
public CodegenModel fromModel(String name, Schema model) {
// Exchange import directives from core model with ours
CodegenModel codegenModel = super.fromModel(name, model);

Set<String> oldImports = codegenModel.imports;
codegenModel.imports = new HashSet<>();

for (String imp : oldImports) {
String newImp = toModelImport(imp);
if (!newImp.isEmpty()) {

if (newImp != null && !newImp.isEmpty()) {
codegenModel.imports.add(newImp);
}
}

if(!codegenModel.isEnum
&& codegenModel.anyOf.size()>1
&& codegenModel.anyOf.contains("std::string")
&& codegenModel.anyOf.contains(STD_STRING)
&& !codegenModel.anyOf.contains("AnyType")
&& codegenModel.interfaces.size()==1
){
Expand Down Expand Up @@ -388,7 +421,7 @@ public String getTypeDeclaration(Schema p) {
Schema inner = ModelUtils.getAdditionalProperties(p);
return getSchemaType(p) + "<std::string, " + getTypeDeclaration(inner) + ">";
} else if (ModelUtils.isByteArraySchema(p)) {
return "std::string";
return STD_STRING;
}
if (ModelUtils.isStringSchema(p)
|| ModelUtils.isDateSchema(p)
Expand All @@ -397,8 +430,14 @@ public String getTypeDeclaration(Schema p) {
return toModelName(openAPIType);
}

String namespace = (String)additionalProperties.get("modelNamespace");
return namespace + "::" + openAPIType;
// Some types might not support namespace
if (this.openAPITypesWithoutModelNamespace.contains(openAPIType)) {
return openAPIType;
}
else {
String namespace = (String) additionalProperties.get("modelNamespace");
return namespace + "::" + openAPIType;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openapitools.codegen.cpppistache;

import java.io.*;
import java.nio.file.Files;
import java.util.*;

import org.openapitools.codegen.*;
import org.openapitools.codegen.config.CodegenConfigurator;

/**
* Abstract test class to make one or multiple generators generate files for one specific input spec
*/
public abstract class AbstractGeneratorsTest {
/**
* Test each with a given input spec
* @param inputSpec The input spec to use
* @return Map of generator and files
* @throws IOException if the test directory cannot be created
*/
protected Map<String, List<File>> eachWith(String inputSpec) throws IOException {
Objects.requireNonNull(inputSpec, "Specify an inputspec to run that test");
Map<String, List<File>> generatedFilesByGenerator = new HashMap<>();

for (final CodegenConfig codegenConfig : CodegenConfigLoader.getAll()) {
generatedFilesByGenerator.put(codegenConfig.getName(), oneWith(codegenConfig.getName(), inputSpec));
}

return generatedFilesByGenerator;
}

/**
* Test each with a given input spec
* @param generatorName the generator name to use
* @param inputSpec The input spec to use
* @return List of generated files
* @throws IOException if the test directory cannot be created
*/
protected List<File> oneWith(String generatorName, String inputSpec) throws IOException {
Objects.requireNonNull(generatorName, "Specify a generatorName to run that test");
Objects.requireNonNull(inputSpec, "Specify an inputspec to run that test");

File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName(generatorName)
.setInputSpec(inputSpec)
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));

final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator();
return generator.opts(clientOptInput).generate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openapitools.codegen.cpppistache;

import java.io.*;
import java.util.*;

import org.slf4j.*;
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;

/**
* Generate from an input spec containing various abstract objects and sets
*/
public class ObjectAnyTypeSetTest extends AbstractGeneratorsTest {
/** Logger. */
private static final Logger LOGGER = LoggerFactory.getLogger(ObjectAnyTypeSetTest.class);

/** A Petstore inputspec with abstract properties added in the Pet */
private static final String INPUT_SPEC = "src/test/resources/3_0/issues-anytype-object-set-petstore-everything.yaml";

/** Soft assert to check all the generators before eventually failing a test */
private final SoftAssert softAssert = new SoftAssert();

/**
* Test some generators with an input spec requiring generation of abstract properties
* @throws IOException if the test folder cannot be created
*/
@Test
public void testSomeWithPetstoreWithAbstract() throws IOException {
// assertGeneratedFiles("c");
// assertGeneratedFiles("cpp-restsdk");
generateFiles("cpp-pistache-server");
// assertGeneratedFiles("typescript");
this.softAssert.assertAll();
}

/**
* Asserts that a generator has produced some files
* @param generatorName The generator name to test
* @return List of files generated
* @throws IOException if the test folder cannot be created
*/
private List<File> generateFiles(String generatorName) throws IOException {
Objects.requireNonNull(generatorName, "A generator name is expected for this assertion");
return oneWith(generatorName, INPUT_SPEC);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
These test aren't useful yet
they only run the generator for a single case
Loading

0 comments on commit fde8c77

Please sign in to comment.