Repository: microsoft/kiota (csharp)

Issue:
Naming issue with GitHub specification
### What are you generating using Kiota, clients or plugins?

API Client/SDK

### In what context or format are you using Kiota?

Nuget tool

### Client library/SDK language

Go

### Describe the bug

(Please see reproduction steps below)

Kiota version: v1.15.0

Build error:

```
sh$ go build ./...
# github.com/octokit/temp/models
models/code_scanning_variant_analysis.go:35:13: undefined: CodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:207:36: undefined: ParseCodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:212:31: undefined: CodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:255:52: undefined: CodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:409:56: undefined: CodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:430:18: undefined: CodeScanningVariantAnalysis_status
models/code_scanning_variant_analysis.go:443:22: undefined: CodeScanningVariantAnalysis_status
```

It's interesting that the errors are limited to this specific model and this specific file. In this case, the _file name_ (CodeScanningVariantAnalysis) minus the extension, is appearing in the file in place of the _type name_ (CodeScanningVariantAnalysisStatus) and a simple find/replace in that file will cause the build to succeed without errors. 


### Expected behavior

I expect `go build ./...` to succeed without any output.

### How to reproduce

Reproduction steps: 

- Download the latest GitHub schema from [here](https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json)
- Using Kiota v1.15.0, run generation like so: `kiota generate -l go --ll trace -o $(pwd)/temp -n github.com/octokit/temp -d schemas/downloaded.json --ebc`
- Change into wherever you generated your code: `cd temp`
- Create a Go module from the generated code: `go mod init github.com/octokit/temp && go mod tidy`
- Run `go build ./...`

### Open API description file

https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json

### Kiota Version

v1.15.0

### Latest Kiota version known to work for scenario above?(Not required)

v1.14.0

### Known Workarounds

- Downgrade to Kiota v1.14.0
- Use a find/replace step after building to replace the filename with the correct type name inside the file

### Configuration

This occurs on any x64-based Ubuntu-derivative system (e.g. GitHub Actions, though that is also my local dev environment). I do not know if it's specific to this configuration.

### Debug output

N/A

### Other information

N/A

Pull request:
Fixes https://github.com/microsoft/kiota/issues/4833

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2cecae252..487299659c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - C# do not report CS0618 in the generated code. [#5229](https://github.com/microsoft/kiota/issues/5229)
 - C# do not decorate method parameter(s) with ObsoleteAttribute. [#5228](https://github.com/microsoft/kiota/issues/5228)
 - Fixed an issue where the generation hint for the workspace experience would be outdated. [#5241](https://github.com/microsoft/kiota/issues/5241)
+- Fixes an issue where the GoPathSegmenter would create the same file name for different elements to lead to missing code due to overwriting of the content [#4833](https://github.com/microsoft/kiota/issues/4833)
 
 ## [1.17.0] - 2024-08-09
 
diff --git a/src/Kiota.Builder/Extensions/StringExtensions.cs b/src/Kiota.Builder/Extensions/StringExtensions.cs
index 1c66ed83d3..e18612aa42 100644
--- a/src/Kiota.Builder/Extensions/StringExtensions.cs
+++ b/src/Kiota.Builder/Extensions/StringExtensions.cs
@@ -51,8 +51,8 @@ public static string TrimQuotes(this string? original) =>
     /// <summary>
     /// Shortens a file name to the maximum allowed length on the file system using a hash to avoid collisions
     /// </summary>
-    /// <param name="fileName">The file name to shorten</param>
-    /// <param name="maxFileNameLength">The maximum length of the file name. Default 251 = 255 - .ext</param>
+    /// <param name="name">The file name to shorten</param>
+    /// <param name="length">The maximum length of the file name. Default 251 = 255 - .ext</param>
     public static string ShortenFileName(this string name, int length = 251) =>
 #pragma warning disable CA1308
         (!string.IsNullOrEmpty(name) && name.Length > length) ? HashString(name).ToLowerInvariant() : name;
diff --git a/src/Kiota.Builder/PathSegmenters/GoPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/GoPathSegmenter.cs
index c13a48e7d9..0a7da43dfa 100644
--- a/src/Kiota.Builder/PathSegmenters/GoPathSegmenter.cs
+++ b/src/Kiota.Builder/PathSegmenters/GoPathSegmenter.cs
@@ -6,7 +6,7 @@
 using Kiota.Builder.Extensions;
 
 namespace Kiota.Builder.PathSegmenters;
-public class GoPathSegmenter : CommonPathSegmenter
+public class GoPathSegmenter(string rootPath, string clientNamespaceName) : CommonPathSegmenter(rootPath, clientNamespaceName)
 {
     private static readonly HashSet<string> specialFileNameSuffixes = new(StringComparer.OrdinalIgnoreCase) {
         "test"       ,
@@ -69,7 +69,6 @@ public class GoPathSegmenter : CommonPathSegmenter
         "wasm"        ,
     };
 
-    public GoPathSegmenter(string rootPath, string clientNamespaceName) : base(rootPath, clientNamespaceName) { }
     public override string FileSuffix => ".go";
     public override IEnumerable<string> GetAdditionalSegment(CodeElement currentElement, string fileName)
     {
@@ -85,7 +84,14 @@ public override string NormalizeFileName(CodeElement currentElement)
         return currentElement switch
         {
             CodeNamespace => "go",
-            _ => GetLastFileNameSegment(currentElement).ToSnakeCase().EscapeSuffix(specialFileNameSuffixes).ShortenFileName(100),
+            _ => GetLastFileNameSegment(currentElement)
+                .Replace("_escaped", "Escaped", StringComparison.OrdinalIgnoreCase)// prevent potential double escaping.
+                .Replace("_", "_escaped_", StringComparison.OrdinalIgnoreCase)// at this point we have the guarantee that the element name is unique based on how child elements are held in Kiota.
+                                                                              // The existence of the '_' character in an element name could make `ToSnakeCase` give the same file name.
+                                                                              // e.g. codeScanningVariantAnalysisStatus and codeScanningVariantAnalysis_status both give code_scanning_variant_analysis
+                                                                              // This shouldn't break anything as golang does not care about filenames.
+                .ToSnakeCase()
+                .EscapeSuffix(specialFileNameSuffixes).ShortenFileName(100),
         };
     }
     public override string NormalizeNamespaceSegment(string segmentName) => segmentName?.ToLowerInvariant() ?? string.Empty;


Test patch:
diff --git a/tests/Kiota.Builder.Tests/PathSegmenters/GoPathSegmenterTests.cs b/tests/Kiota.Builder.Tests/PathSegmenters/GoPathSegmenterTests.cs
index 7251d54cf6..8d6081f535 100644
--- a/tests/Kiota.Builder.Tests/PathSegmenters/GoPathSegmenterTests.cs
+++ b/tests/Kiota.Builder.Tests/PathSegmenters/GoPathSegmenterTests.cs
@@ -6,11 +6,7 @@ namespace Kiota.Builder.Tests.PathSegmenters;
 
 public class GoPathSegmenterTests
 {
-    private readonly GoPathSegmenter segmenter;
-    public GoPathSegmenterTests()
-    {
-        segmenter = new GoPathSegmenter("D:\\source\\repos\\kiota-sample", "client");
-    }
+    private readonly GoPathSegmenter segmenter = new("D:\\source\\repos\\kiota-sample", "client");
 
     [Fact]
     public void GoPathSegmenterGeneratesCorrectFileName()
@@ -39,4 +35,34 @@ public void GoPathSegmenterGeneratesNamespaceFolderName()
         var normalizedNamespace = segmenter.NormalizeNamespaceSegment(namespaceName);
         Assert.Equal("microsoft.graph", normalizedNamespace);// the file name should be lower case
     }
+
+    [Fact]
+    public void GoPathSegmenterGeneratesDistinctFileNames()
+    {
+        var fileName1 = segmenter.NormalizeFileName(new CodeClass
+        {
+            Name = "codeScanningVariantAnalysisStatus"
+        });
+        var fileName2 = segmenter.NormalizeFileName(new CodeClass
+        {
+            Name = "codeScanningVariantAnalysis_status"
+        });
+        Assert.NotEqual(fileName1, fileName2);// the file name should be Different!
+        Assert.Equal("code_scanning_variant_analysis_status", fileName1);// the file name should be camel cased!
+        Assert.Equal("code_scanning_variant_analysis_escaped_status", fileName2);// the file name should be camel cased!
+    }
+
+    [Theory]
+    [InlineData("adminWindows_escaped", "admin_windows_escaped")]//This technically won't be an expected escaped name in go as its refiner appends `Escaped`
+    [InlineData("adminWindows_Escaped", "admin_windows_escaped")]//This technically won't be an expected escaped name in go as its refiner appends `Escaped`
+    [InlineData("adminWindowsescaped", "admin_windowsescaped")]//This technically won't be an expected escaped name in go as its refiner appends `Escaped`
+    [InlineData("adminWindowsEscaped", "admin_windows_escaped")]//This IS an expected escaped name in go as its refiner appends `Escaped`
+    public void GoPathSegmenterGeneratesEscapedAlreadyEscapedSpecialClassName(string inputClassName, string expectedFileName)
+    {
+        var fileName = segmenter.NormalizeFileName(new CodeClass
+        {
+            Name = inputClassName
+        });
+        Assert.Equal(expectedFileName, fileName); // file name should be snake case and escaped
+    }
 }