Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ
if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), static x => x.Name.ToFirstCharacterUpperCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath))
writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => {primaryMessageCodePath} ?? string.Empty; }}");
else
writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => base.Message; }}");
writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => $\"{{ResponseStatusCode}}: {{base.Message}}\"; }}");
break;
case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped:
writer.WriteLine($"[QueryParameter(\"{codeElement.SerializationName}\")]");
Expand Down
3 changes: 2 additions & 1 deletion src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ
break;
case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition:
writer.WriteLine("@override");
goto default;
writer.WriteLine($"{propertyType} get {codeElement.Name} => '$responseStatusCode: ${{super.message}}';");
Comment thread
baywet marked this conversation as resolved.
break;
case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped:
writer.WriteLine($"/// @QueryParameter('{codeElement.SerializationName}')");
goto default;
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private static void WriteErrorMethodOverride(CodeClass parentClass, LanguageWrit
}
else
{
writer.WriteLine("return m.ApiError.Error()");
writer.WriteLine("return fmt.Sprintf(\"%d: %s\", m.ResponseStatusCode, m.ApiError.Error())");
}
}
private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer)
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private static void WriteErrorMethodOverride(CodeClass parentClass, LanguageWrit
}
else
{
writer.WriteLine("return super.getMessage();");
writer.WriteLine("return getResponseStatusCode() + \": \" + super.getMessage();");
}
}
private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer)
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private void WriteErrorMessageOverride(CodeClass parentClass, LanguageWriter wri
}
else
{
writer.WriteLine("return parent::getMessage();");
writer.WriteLine("return $this->getResponseStatusCode() . ': ' . parent::getMessage();");
}
}
private const string UrlTemplateTempVarName = "$urlTplParams";
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
writer.WriteLine("return ''");
}
else
writer.WriteLine("return super().message");
writer.WriteLine("return f'{self.response_status_code}: {super().message}'");
writer.DecreaseIndent();
break;
}
Expand Down
20 changes: 17 additions & 3 deletions src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,13 @@ private void WriteDeserializerFunctionProperties(CodeParameter param, CodeInterf
WritePropertyDeserializationBlock(otherProp, param, primaryErrorMapping, primaryErrorMappingKey, codeFile, writer);
}

// Fallback: If no primaryErrorMappingKey, emit error message assignment here
if (string.IsNullOrEmpty(primaryErrorMappingKey) && !string.IsNullOrEmpty(primaryErrorMapping))
{
writer.WriteLine("// Fallback error message assignment for error definitions without primary message");
writer.WriteLine(primaryErrorMapping.Trim());
}

writer.CloseBlock();
}

Expand All @@ -703,10 +710,17 @@ private static (string, string) GetPrimaryErrorMapping(CodeFunction codeFunction
var primaryErrorMappingKey = string.Empty;
var parentClass = codeFunction.OriginalMethodParentClass;

if (parentClass.IsErrorDefinition && parentClass.AssociatedInterface is not null && parentClass.AssociatedInterface.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterLowerCase(), static x => x.Name.ToFirstCharacterLowerCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath))
if (parentClass.IsErrorDefinition)
{
primaryErrorMapping = $" {param.Name.ToFirstCharacterLowerCase()}.message = {param.Name.ToFirstCharacterLowerCase()}.{primaryMessageCodePath} ?? \"\";";
primaryErrorMappingKey = primaryMessageCodePath.Split("?.", StringSplitOptions.RemoveEmptyEntries)[0];
if (parentClass.AssociatedInterface is not null && parentClass.AssociatedInterface.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterLowerCase(), static x => x.Name.ToFirstCharacterLowerCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath))
{
primaryErrorMapping = $" {param.Name.ToFirstCharacterLowerCase()}.message = {param.Name.ToFirstCharacterLowerCase()}.{primaryMessageCodePath} ?? \"\";";
primaryErrorMappingKey = primaryMessageCodePath.Split("?.", StringSplitOptions.RemoveEmptyEntries)[0];
}
else
{
primaryErrorMapping = $" {param.Name.ToFirstCharacterLowerCase()}.message = `${{{param.Name.ToFirstCharacterLowerCase()}.responseStatusCode}}: ${{super.message ?? \"\"}}`;";
}
}

return (primaryErrorMapping, primaryErrorMappingKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,5 +250,29 @@ public void WritesMessageOverrideOnPrimary()
// Then
Assert.Contains("public override string Message { get => Prop1 ?? string.Empty; }", result);
}

[Fact]
public void WritesMessageOverrideWithStatusCodeWhenNoPrimaryMessage()
{
// Given
parentClass.IsErrorDefinition = true;
// No primary error message property added
var overrideProperty = parentClass.AddProperty(new CodeProperty
{
Name = "Message",
Kind = CodePropertyKind.ErrorMessageOverride,
Type = new CodeType
{
Name = "string",
},
}).First();

// When
writer.Write(overrideProperty);
var result = tw.ToString();

// Then
Assert.Contains("public override string Message { get => $\"{ResponseStatusCode}: {base.Message}\"; }", result);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,15 @@ public void DoesntWritePropertiesExistingInParentType()
var result = tw.ToString();
Assert.Empty(result);
}

[Fact]
public void WriteErrorMessageOverrideWithStatusCodeWhenNoPrimary()
{
property.Kind = CodePropertyKind.ErrorMessageOverride;
parentClass.IsErrorDefinition = true;
writer.Write(property);
var result = tw.ToString();
Assert.Contains("@override", result);
Assert.Contains("get propertyName => '$responseStatusCode: ${super.message}';", result);
}
}
33 changes: 33 additions & 0 deletions tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,39 @@ public void WritesMessageOverrideOnPrimary()
Assert.Contains("return *(m.GetProp1()", result);
}

[Fact]
public void WritesMessageOverrideWithStatusCodeWhenNoPrimary()
{
// Given
parentClass = root.AddClass(new CodeClass
{
Name = "parentClass",
IsErrorDefinition = true,
Kind = CodeClassKind.Model,
}).First();
// No primary error message property added
var method = parentClass.AddMethod(new CodeMethod
{
Kind = CodeMethodKind.ErrorMessageOverride,
ReturnType = new CodeType
{
Name = "string",
IsNullable = false,
},
IsAsync = false,
IsStatic = false,
Name = "Error"
}).First();

// When
writer.Write(method);
var result = tw.ToString();

// Then
Assert.Contains("Error()(string) {", result);
Assert.Contains("return fmt.Sprintf(\"%d: %s\", m.ResponseStatusCode, m.ApiError.Error())", result);
}

[Fact]
public void WritesRequestGeneratorAcceptHeaderQuotes()
{
Expand Down
34 changes: 34 additions & 0 deletions tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2166,6 +2166,40 @@ public void WritesMessageOverrideOnPrimary()
Assert.Contains("return this.getProp1()", result);
}

[Fact]
public void WritesMessageOverrideWithStatusCodeWhenNoPrimary()
{
// Given
parentClass = root.AddClass(new CodeClass
{
Name = "parentClass",
IsErrorDefinition = true,
Kind = CodeClassKind.Model,
}).First();
// No primary error message property added
var method = parentClass.AddMethod(new CodeMethod
{
Kind = CodeMethodKind.ErrorMessageOverride,
ReturnType = new CodeType
{
Name = "String",
IsNullable = false,
},
IsAsync = false,
IsStatic = false,
Name = "getErrorMessage"
}).First();

// When
writer.Write(method);
var result = tw.ToString();

// Then
Assert.Contains("@Override", result);
Assert.Contains("String getErrorMessage() ", result);
Assert.Contains("return getResponseStatusCode() + \": \" + super.getMessage();", result);
}

[Fact]
public void WritesRequestGeneratorAcceptHeaderQuotes()
{
Expand Down
26 changes: 26 additions & 0 deletions tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,32 @@ public async Task WriteErrorMessageOverrideAsync()

Assert.Contains("return $primaryError->getMessage() ?? '';", result);
}

[Fact]
public async Task WriteErrorMessageOverrideWithStatusCodeWhenNoPrimaryAsync()
{
setup();
var error401 = root.AddClass(new CodeClass
{
Name = "Error401",
IsErrorDefinition = true
}).First();
// No primary error message property added

var codeMethod = new CodeMethod
{
Kind = CodeMethodKind.ErrorMessageOverride,
ReturnType = new CodeType { Name = "string" },
SimpleName = "getPrimaryErrorMessage",
};
error401.AddMethod(codeMethod);
await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.PHP }, root);
_codeMethodWriter.WriteCodeElement(codeMethod, languageWriter);
var result = stringWriter.ToString();

Assert.Contains("return $this->getResponseStatusCode() . ': ' . parent::getMessage();", result);
}

[Fact]
public async Task WritesRequestExecutorForEnumTypesAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ public void WritePrimaryErrorMessagePropertyOption1()
var result = tw.ToString();
Assert.Contains("super().message", result);
}

[Fact]
public void WriteMessageOverrideWithStatusCodeWhenNoPrimary()
{
property.Kind = CodePropertyKind.ErrorMessageOverride;
parentClass.IsErrorDefinition = true;
writer.Write(property);
var result = tw.ToString();
Assert.Contains("return f'{self.response_status_code}: {super().message}'", result);
}

[Fact]
public void WritePrimaryErrorMessagePropertyOption2()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,87 @@ public void WritesByteArrayPropertyDeserialization()
Assert.Contains("\"property\": n => { model.property = n.getByteArrayValue(); }", result, StringComparison.Ordinal);
}

[Fact]
public void WritesErrorMessageAssignmentWithStatusCodeWhenNoPrimary()
{
var errorClass = root.AddClass(new CodeClass
{
Name = "Error4XX",
IsErrorDefinition = true,
Kind = CodeClassKind.Model,
}).First();

// Create associated interface (required for TypeScript)
var errorInterface = root.AddInterface(new CodeInterface
{
Name = "Error4XXInterface",
Kind = CodeInterfaceKind.Model,
OriginalClass = errorClass
}).First();

// Add the same property to both class and interface
var codeProperty = new CodeProperty
{
Name = "code",
Kind = CodePropertyKind.Custom,
Type = new CodeType { Name = "string" },
};
errorClass.AddProperty(codeProperty);
errorInterface.AddProperty(new CodeProperty
{
Name = "code",
Kind = CodePropertyKind.Custom,
Type = new CodeType { Name = "string" },
});

// Link class to interface
errorClass.AssociatedInterface = errorInterface;

// No primary error message property added - this should trigger our fallback

// Create deserializer method manually (like the refiner would)
var deserializerMethod = errorClass.AddMethod(new CodeMethod
{
Name = "deserializeIntoError4XX",
Kind = CodeMethodKind.Deserializer,
IsStatic = true,
ReturnType = new CodeType
{
Name = "Record<string, (node: ParseNode) => void>",
},
}).First();

deserializerMethod.AddParameter(new CodeParameter
{
Name = "error4XX",
Kind = CodeParameterKind.RequestBody,
Type = new CodeType
{
Name = "Error4XXInterface",
TypeDefinition = errorInterface,
},
});

var function = new CodeFunction(deserializerMethod);
root.TryAddCodeFile("error4XX", function);
writer.Write(function);
var result = tw.ToString();

// The result should contain deserializer properties and the error message assignment
Assert.Contains("error4XX.code = n.getStringValue()", result); // Basic property assignment should exist

// The error message assignment should be generated because this is an error definition without primary message
// It should contain our enhancement that includes the status code
var expectedErrorMessage = "error4XX.message = `${error4XX.responseStatusCode}: ${super.message ?? \"\"}`";
Assert.Contains(expectedErrorMessage, result);

// Verify the error message assignment appears exactly once
var occurrences = result.Split(new[] { expectedErrorMessage }, StringSplitOptions.None).Length - 1;
Assert.Equal(1, occurrences);

Assert.Contains("deserializeIntoError4XX", result);
}

[Fact]
public async Task WritesOneOfWithInheritanceDeserializationAsync()
{
Expand Down
Loading