Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ module {{moduleName}}

# Returns Auth Settings hash for api client.
def auth_settings
{{#authMethods.0}}
Hash{
{{#authMethods}}
{{#isApiKey}}
Expand Down Expand Up @@ -250,6 +251,10 @@ module {{moduleName}}
{{/isOAuth}}
{{/authMethods}}
}
{{/authMethods.0}}
{{^authMethods}}
{} of String => Hash(Symbol, String)
{{/authMethods}}
end

# Returns an array of Server setting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,77 @@ public void testBooleanDefaultValue() throws Exception {
}
}

@Test
public void testAuthSettingsWithNoAuthMethodsEmitsValidCrystal() throws Exception {
// Regression test: when an OpenAPI spec has no recognized auth methods,
// the generated configuration.cr's auth_settings method must not emit
// a bare `Hash{}` literal, which is invalid Crystal. Crystal requires
// `{} of K => V` for empty hash literals.
final File output = Files.createTempDirectory("test").toFile();
output.mkdirs();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/2_0/pathWithHtmlEntity.yaml");
CodegenConfig codegenConfig = new CrystalClientCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);

DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(clientOptInput).generate();
boolean configFileGenerated = false;
for (File file : files) {
if (file.getName().equals("configuration.cr")) {
configFileGenerated = true;
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
// Bug: the previous template emitted `Hash{\n }` for empty
// auth methods, which Crystal rejects with:
// Error: for empty hashes use '{} of KeyType => ValueType'
Assert.assertFalse(content.contains("Hash{\n }"),
"configuration.cr must not contain an empty `Hash{}` literal");
Assert.assertFalse(content.contains("Hash{}"),
"configuration.cr must not contain an empty `Hash{}` literal");
// Fix: emit a typed empty hash literal that compiles in Crystal.
assertTrue(content.contains("{} of String => Hash(Symbol, String)"),
"configuration.cr must emit a typed empty hash literal in auth_settings");
}
}
if (!configFileGenerated) {
fail("configuration.cr file is not generated!");
}
}

@Test
public void testAuthSettingsWithAuthMethodsStillEmitsHashLiteral() throws Exception {
// Ensure the empty-auth fix did not regress the populated case.
final File output = Files.createTempDirectory("test").toFile();
output.mkdirs();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/crystal/petstore.yaml");
CodegenConfig codegenConfig = new CrystalClientCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);

DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(clientOptInput).generate();
boolean configFileGenerated = false;
for (File file : files) {
if (file.getName().equals("configuration.cr")) {
configFileGenerated = true;
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
assertTrue(content.contains("Hash{"),
"configuration.cr should still emit `Hash{` for populated auth methods");
Assert.assertFalse(content.contains("{} of String => Hash(Symbol, String)"),
"configuration.cr should not emit empty hash literal when auth methods exist");
}
}
if (!configFileGenerated) {
fail("configuration.cr file is not generated!");
}
}

@Test
public void testSanitizeModelName() throws Exception {
final CrystalClientCodegen codegen = new CrystalClientCodegen();
Expand Down
Loading