diff --git a/.gitignore b/.gitignore index d7488adadf1..362fe6320fa 100644 --- a/.gitignore +++ b/.gitignore @@ -258,3 +258,4 @@ Microsoft.TemplateEngine.VC.db #Rider .idea/ +.nuget/ diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs index ca63b1b535a..d9b45444d8c 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs @@ -131,6 +131,12 @@ private static IReadOnlyDictionary LoadPost foreach (var postActionParts in strings.GroupBy(p => p.NameParts.FirstOrDefault())) { + if (string.IsNullOrEmpty(postActionParts.Key)) + { + // Post action with no ID. Ignore. + continue; + } + string postActionId = postActionParts.Key; string? description = postActionParts.SingleOrDefault(p => p.NameParts.Skip(1).FirstOrDefault() == "description").LocalizedString; var instructions = LoadManualInstructionModels(postActionParts @@ -162,6 +168,12 @@ private static IReadOnlyDictionary LoadManualInstructionModels(I foreach (var instructionParts in strings.GroupBy(p => p.NameParts.FirstOrDefault())) { + if (string.IsNullOrEmpty(instructionParts.Key)) + { + // Instruction with no ID. Ignore. + continue; + } + string id = instructionParts.Key; string? text = instructionParts.SingleOrDefault(p => p.NameParts.Skip(1).FirstOrDefault() == "text").LocalizedString; results[id] = text; diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs index fb7f8c12a9b..c6d1df84757 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs @@ -109,6 +109,8 @@ public void CanReadDescription(string fileContent, bool errorExpected, string? e [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/displayName": "localizedSymbol" }""", false, "someSymbol", "localizedSymbol", "(null)")] [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/description": "localizedSymbolDescription" }""", false, "someSymbol", "(null)", "localizedSymbolDescription")] [InlineData(/*lang=json*/ """{ description: ""}""", false, null, null, null)] + // Test case for NullReferenceException fix: malformed symbol key with only "symbols/" prefix + [InlineData(/*lang=json,strict*/ """{ "symbols/": "test" }""", false, null, null, null)] public void CanReadNonChoiceSymbol( string fileContent, bool errorExpected, @@ -244,6 +246,10 @@ public void CanReadChoiceSymbol( [InlineData(/*lang=json*/ """{ description: ""}""", false, null, null, null)] [InlineData(/*lang=json,strict*/ """{ "postActions/pa0/description": "localizedDescription" }""", false, "pa0", "localizedDescription", "(null)")] [InlineData(/*lang=json,strict*/ """{ "postActions/pa0/manualInstructions/first/text": "localizedDescription" }""", false, "pa0", "(null)", "first*localizedDescription")] + // Test case for NullReferenceException fix: malformed postAction key with only "postActions/" prefix + [InlineData(/*lang=json,strict*/ """{ "postActions/": "test" }""", false, null, null, null)] + // Test case for NullReferenceException fix: malformed manualInstruction key with missing instruction id + [InlineData(/*lang=json,strict*/ """{ "postActions/pa0/manualInstructions//text": "test" }""", false, "pa0", "(null)", "(null)")] public void CanReadPostAction( string fileContent, bool errorExpected,