fix(cpp-httplib-server): generate top-level enum models - #24795
stefanwitkowskiwmb wants to merge 18 commits into
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
3 issues found across 46 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h">
<violation number="1" location="samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h:11">
P3: Every regenerated model header now contains a duplicated `#include <string>`: the template emits it unconditionally while `filteredImports` (from `postProcessAllModels`) emits it again for each model with a string member. It compiles because of the standard header guard, but it clutters every generated header. `model-header.mustache` should not hardcode `#include <string>`; let `filteredImports` provide it (as the master template did), or dedupe `<string>` in the import filter.</violation>
</file>
<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h">
<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h:11">
P3: Generated model headers now emit a duplicate `#include <string>` for every model with a string member. The template hardcodes `#include <string>` while `filteredImports` (CppHttplibServerCodegen.java) already emits it for string-typed vars, so the two overlap in the output. Harmless at compile time, but it regresses generated-code cleanliness across all string-membered models. Drop the hardcoded `#include <string>` from model-header.mustache; the enum and string-member headers don't need it from the template since filteredImports supplies it (enum serialization uses string literals only).</violation>
</file>
<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h">
<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h:11">
P3: Every generated model header in this PR now emits `#include <string>` twice: once from the template's new hardcoded include and once from the model's filtered imports. The template at model-header.mustache line 8 unconditionally writes `#include <string>` before `{{#vendorExtensions.filteredImports}}`, which itself also emits `<string>` for any model with a std::string field, so the two sources collide. De-duplicate (e.g. drop `<string>` from the template's hardcoded block when it is already in the model's imports) so generated output contains a single include.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 46 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
The isStringEnum fallback added in f368b5a had no test that distinguished it from the previous ModelUtils.isStringSchema check. ModelUtils.getType returns the first element of a 3.1 type set, so a `type: [null, string]` enum reports its type as "null": isStringSchema is false while isEnum is true, and model-header.mustache then emits `j = available;` instead of `j = "available";`, which does not compile. Reverting CppHttplibServerCodegen to the plain isStringSchema check makes this test fail. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…evel enums
The existing enum tests only assert the isStringEnum vendor extension on
the fromModel result. That flag is just the input to model-header.mustache,
so a break in the template itself -- a renamed flag, an inverted section --
passed the whole suite unnoticed.
Add a test that builds a string-backed and an integer-backed top-level enum
schema, runs DefaultGenerator over them, and asserts on the rendered enum
headers: quoted values for the former, bare values for the latter, plus the
inverse via assertFileNotContains. Renaming vendorExtensions.isStringEnum
throughout model-header.mustache makes it fail.
Also add an integer-backed top-level enum to feature-test.json and
regenerate its sample. The template's `{{^vendorExtensions.isStringEnum}}`
branch had no checked-in sample output, since the spec carried a top-level
string enum but no integer one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…/github.com/stefanwitkowskiwmb/openapi-generator into bugfix/httplib-server_top_level_enum_schema
|
thanks for the PR can you please review the build failure when you've time? https://github.com/OpenAPITools/openapi-generator/actions/runs/34101485793/job/106096543175?pr=24795 |
…ot directly related to nlohmann but are more general in nature.
There was a problem hiding this comment.
3 issues found across 12 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache:31">
P1: When a top-level string enum contains a quote, backslash, or control character, this raw interpolation generates an invalid or changed C++ literal in both `to_json` and `from_json`. Generate a C++-escaped string literal in the codegen metadata and emit that literal without adding another pair of quotes.</violation>
</file>
<file name="samples/server/petstore/cpp-httplib-server/feature-test/README.md">
<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/README.md:527">
P3: The added enum snippets document `models::TopLevelPriority` and `models::TopLevelStatus` without an `UNSPECIFIED` entry, but the same README's "### Enum Handling" section (line ~1049) promises that "All generated enums automatically include an `UNSPECIFIED` value as the first enum entry". Embedded enums generated elsewhere in this sample (e.g. `EnumTypes.h`, `CardType.h`) do start with `UNSPECIFIED`, so the new top-level enums are generated differently from the pattern this README documents. The two sections now contradict each other, and users following the README's Enum Handling guidance will look for `TopLevelPriority::UNSPECIFIED` and won't find it. Either align the top-level enum generation with the embedded-enum pattern (add the `UNSPECIFIED` entry) or update the "Enum Handling" claim so the generated documentation is consistent.</violation>
</file>
<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/TopLevelStatus.h">
<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/TopLevelStatus.h:17">
P3: The enum body is emitted with whitespace-only lines (` `) between enumerators, producing trailing-whitespace lines and extra vertical padding in the generated header. This comes from the enum section of `model-header.mustache`, which puts each `{{name}}` and the closing `{{/enumVars}}` on their own indented lines. The same pattern appears in `TopLevelPriority.h`, and both `.cpp` files also start with an empty first line (from the blank first line in `model-source.mustache`). Collapse the enumerators onto a single line in the template so regenerated samples are free of trailing whitespace.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| switch (value) | ||
| { | ||
| {{#allowableValues}}{{#enumVars}} | ||
| case {{vendorExtensions.modelClassName}}::{{name}}: j = {{#vendorExtensions.isStringEnum}}"{{{value}}}"{{/vendorExtensions.isStringEnum}}{{^vendorExtensions.isStringEnum}}{{value}}{{/vendorExtensions.isStringEnum}}; break; |
There was a problem hiding this comment.
P1: When a top-level string enum contains a quote, backslash, or control character, this raw interpolation generates an invalid or changed C++ literal in both to_json and from_json. Generate a C++-escaped string literal in the codegen metadata and emit that literal without adding another pair of quotes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache, line 31:
<comment>When a top-level string enum contains a quote, backslash, or control character, this raw interpolation generates an invalid or changed C++ literal in both `to_json` and `from_json`. Generate a C++-escaped string literal in the codegen metadata and emit that literal without adding another pair of quotes.</comment>
<file context>
@@ -16,6 +16,38 @@
+ switch (value)
+ {
+ {{#allowableValues}}{{#enumVars}}
+ case {{vendorExtensions.modelClassName}}::{{name}}: j = {{#vendorExtensions.isStringEnum}}"{{{value}}}"{{/vendorExtensions.isStringEnum}}{{^vendorExtensions.isStringEnum}}{{value}}{{/vendorExtensions.isStringEnum}}; break;
+ {{/enumVars}}{{/allowableValues}}
+ default: throw nlohmann::json::type_error::create(302, "Invalid value for {{vendorExtensions.modelClassName}}", &j);
</file context>
|
|
||
| ```cpp | ||
| // Select an enum value | ||
| auto model = models::TopLevelPriority::_0; |
There was a problem hiding this comment.
P3: The added enum snippets document models::TopLevelPriority and models::TopLevelStatus without an UNSPECIFIED entry, but the same README's "### Enum Handling" section (line ~1049) promises that "All generated enums automatically include an UNSPECIFIED value as the first enum entry". Embedded enums generated elsewhere in this sample (e.g. EnumTypes.h, CardType.h) do start with UNSPECIFIED, so the new top-level enums are generated differently from the pattern this README documents. The two sections now contradict each other, and users following the README's Enum Handling guidance will look for TopLevelPriority::UNSPECIFIED and won't find it. Either align the top-level enum generation with the embedded-enum pattern (add the UNSPECIFIED entry) or update the "Enum Handling" claim so the generated documentation is consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/cpp-httplib-server/feature-test/README.md, line 527:
<comment>The added enum snippets document `models::TopLevelPriority` and `models::TopLevelStatus` without an `UNSPECIFIED` entry, but the same README's "### Enum Handling" section (line ~1049) promises that "All generated enums automatically include an `UNSPECIFIED` value as the first enum entry". Embedded enums generated elsewhere in this sample (e.g. `EnumTypes.h`, `CardType.h`) do start with `UNSPECIFIED`, so the new top-level enums are generated differently from the pattern this README documents. The two sections now contradict each other, and users following the README's Enum Handling guidance will look for `TopLevelPriority::UNSPECIFIED` and won't find it. Either align the top-level enum generation with the embedded-enum pattern (add the `UNSPECIFIED` entry) or update the "Enum Handling" claim so the generated documentation is consistent.</comment>
<file context>
@@ -520,6 +520,32 @@ std::string jsonString = json.dump();
+
+```cpp
+// Select an enum value
+auto model = models::TopLevelPriority::_0;
+
+// Serialize to JSON via the generated to_json free function
</file context>
There was a problem hiding this comment.
@wing328
I am considering what is the reason of automatically adding UNSPECIFIED? In my opinion if user require UNSPECIFIED, UNSET or NONE it should be listed in openapi specs. Now we can have enum value in C++, that don't have equivalent in generated client code (ex. typescript). I can rework README or add it to top level Enum but I'm not sure what is desired way. For my needs i do not need it at all, because where i expect it I add it into specs.
What is your call?
|
|
||
| enum class TopLevelStatus { | ||
|
|
||
| ACTIVE, |
There was a problem hiding this comment.
P3: The enum body is emitted with whitespace-only lines ( ) between enumerators, producing trailing-whitespace lines and extra vertical padding in the generated header. This comes from the enum section of model-header.mustache, which puts each {{name}} and the closing {{/enumVars}} on their own indented lines. The same pattern appears in TopLevelPriority.h, and both .cpp files also start with an empty first line (from the blank first line in model-source.mustache). Collapse the enumerators onto a single line in the template so regenerated samples are free of trailing whitespace.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/cpp-httplib-server/feature-test/models/TopLevelStatus.h, line 17:
<comment>The enum body is emitted with whitespace-only lines (` `) between enumerators, producing trailing-whitespace lines and extra vertical padding in the generated header. This comes from the enum section of `model-header.mustache`, which puts each `{{name}}` and the closing `{{/enumVars}}` on their own indented lines. The same pattern appears in `TopLevelPriority.h`, and both `.cpp` files also start with an empty first line (from the blank first line in `model-source.mustache`). Collapse the enumerators onto a single line in the template so regenerated samples are free of trailing whitespace.</comment>
<file context>
@@ -0,0 +1,65 @@
+
+enum class TopLevelStatus {
+
+ ACTIVE,
+
+ INACTIVE,
</file context>
PR checklist
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
Fix for #23902
@ravinikam @stkrwork @etherealjoy @MartinDelille @muttleyxd @aminya
Summary by cubic
Fixes the
cpp-httplib-servergenerator so top-level enum schemas are generated asenum classtypes withto_json/from_jsonhelpers; previously standalone enum models were skipped. Addresses #23902."active", notACTIVE); integer-backed enums serialize as raw JSON numbers. String values are detected even when the declared type isn't plainlystring(e.g. OpenAPI 3.1type: [null, string]).to_json/from_jsonfor top-level enums thrownlohmann::json::type_errorfor values outside the declared set; property-levelToString/FromStringkeep their existing behavior (empty string fallback andstd::invalid_argument).TopLevelStatusandTopLevelPriorityto the feature-test spec with tests asserting the renderedto_json/from_jsonoutput.Written for commit 112e3e1. Summary will update on new commits.