diff --git a/Open-XML-SDK.slnx b/Open-XML-SDK.slnx
index e5f71b362..c8a87f159 100644
--- a/Open-XML-SDK.slnx
+++ b/Open-XML-SDK.slnx
@@ -48,6 +48,7 @@
+
diff --git a/gen/DocumentFormat.OpenXml.Generator.Models/DocumentFormat.OpenXml.Generator.Models.csproj b/gen/DocumentFormat.OpenXml.Generator.Models/DocumentFormat.OpenXml.Generator.Models.csproj
index 6a11c3d57..11116f580 100644
--- a/gen/DocumentFormat.OpenXml.Generator.Models/DocumentFormat.OpenXml.Generator.Models.csproj
+++ b/gen/DocumentFormat.OpenXml.Generator.Models/DocumentFormat.OpenXml.Generator.Models.csproj
@@ -14,4 +14,7 @@
+
+
+
\ No newline at end of file
diff --git a/gen/DocumentFormat.OpenXml.Generator.Models/Generators/Linq/ValidIdentifierHelper.cs b/gen/DocumentFormat.OpenXml.Generator.Models/Generators/Linq/ValidIdentifierHelper.cs
index 64843fe7b..162dabfb5 100644
--- a/gen/DocumentFormat.OpenXml.Generator.Models/Generators/Linq/ValidIdentifierHelper.cs
+++ b/gen/DocumentFormat.OpenXml.Generator.Models/Generators/Linq/ValidIdentifierHelper.cs
@@ -113,9 +113,9 @@ public static bool IsValidIdentifier(string value)
return false;
}
}
- else
+ else if (value.Length < 2)
{
- value = value.Substring(1);
+ return false;
}
return true;
diff --git a/test/DocumentFormat.OpenXml.Generator.Models.Tests/DocumentFormat.OpenXml.Generator.Models.Tests.csproj b/test/DocumentFormat.OpenXml.Generator.Models.Tests/DocumentFormat.OpenXml.Generator.Models.Tests.csproj
new file mode 100644
index 000000000..8b23226b8
--- /dev/null
+++ b/test/DocumentFormat.OpenXml.Generator.Models.Tests/DocumentFormat.OpenXml.Generator.Models.Tests.csproj
@@ -0,0 +1,15 @@
+
+
+
+ $(TestTargetFrameworks)
+ true
+ false
+ Exe
+ enable
+
+
+
+
+
+
+
diff --git a/test/DocumentFormat.OpenXml.Generator.Models.Tests/ValidIdentifierHelperTests.cs b/test/DocumentFormat.OpenXml.Generator.Models.Tests/ValidIdentifierHelperTests.cs
new file mode 100644
index 000000000..0337f65b8
--- /dev/null
+++ b/test/DocumentFormat.OpenXml.Generator.Models.Tests/ValidIdentifierHelperTests.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using DocumentFormat.OpenXml.Generator;
+using Xunit;
+
+namespace DocumentFormat.OpenXml.Generator.Models.Tests;
+
+public class ValidIdentifierHelperTests
+{
+ [Fact]
+ public void NullReturnsFalse()
+ {
+ Assert.False(ValidIdentifierHelper.IsValidIdentifier(null!));
+ }
+
+ [Fact]
+ public void EmptyStringReturnsFalse()
+ {
+ Assert.False(ValidIdentifierHelper.IsValidIdentifier(string.Empty));
+ }
+
+ [Fact]
+ public void LongerThan512ReturnsFalse()
+ {
+ Assert.False(ValidIdentifierHelper.IsValidIdentifier(new string('a', 513)));
+ }
+
+ [Fact]
+ public void Exactly512ReturnsTrue()
+ {
+ Assert.True(ValidIdentifierHelper.IsValidIdentifier(new string('a', 512)));
+ }
+
+ [Fact]
+ public void KeywordReturnsFalse()
+ {
+ Assert.False(ValidIdentifierHelper.IsValidIdentifier("class"));
+ }
+
+ [Fact]
+ public void NonKeywordReturnsTrue()
+ {
+ Assert.True(ValidIdentifierHelper.IsValidIdentifier("myVariable"));
+ }
+
+ [Fact]
+ public void AtPrefixedKeywordReturnsTrue()
+ {
+ Assert.True(ValidIdentifierHelper.IsValidIdentifier("@class"));
+ }
+
+ [Fact]
+ public void AtPrefixedNonKeywordReturnsTrue()
+ {
+ Assert.True(ValidIdentifierHelper.IsValidIdentifier("@myVariable"));
+ }
+
+ [Fact]
+ public void AtAloneReturnsFalse()
+ {
+ // "@" alone is not a valid identifier — after stripping '@', the remaining value is empty
+ Assert.False(ValidIdentifierHelper.IsValidIdentifier("@"));
+ }
+}