From 7863e84bc46de70683a08e6f5f5c09788bd3b400 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:55:14 +0000 Subject: [PATCH 1/7] Initial plan for issue From 806731d3b0fc9af8281add6463ff4e9e4ec9080d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:05:51 +0000 Subject: [PATCH 2/7] Add fast-path optimizations for Char.IsDigit in performance-critical paths Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- src/Build.UnitTests/Scanner_Tests.cs | 21 +++++++++++++++++++ .../Conditionals/CharacterUtilities.cs | 11 +++++++--- src/Build/Evaluation/Conditionals/Scanner.cs | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Build.UnitTests/Scanner_Tests.cs b/src/Build.UnitTests/Scanner_Tests.cs index da75fd75436..5d98f7cdf10 100644 --- a/src/Build.UnitTests/Scanner_Tests.cs +++ b/src/Build.UnitTests/Scanner_Tests.cs @@ -562,5 +562,26 @@ public void NegativeTests() Scanner lexer = new Scanner("'$(DEBUG) == true", ParserOptions.AllowAll); Assert.False(lexer.Advance()); } + + /// + /// Tests the fast-path IsDigit method in CharacterUtilities. + /// + [Fact] + public void CharacterUtilities_IsDigit_WorksCorrectly() + { + // Test ASCII digits + for (char c = '0'; c <= '9'; c++) + { + Assert.True(CharacterUtilities.IsDigit(c), $"Character '{c}' should be identified as a digit"); + } + + // Test non-digit characters + Assert.False(CharacterUtilities.IsDigit('/'), "Character '/' should not be identified as a digit"); + Assert.False(CharacterUtilities.IsDigit(':'), "Character ':' should not be identified as a digit"); + Assert.False(CharacterUtilities.IsDigit('a'), "Character 'a' should not be identified as a digit"); + Assert.False(CharacterUtilities.IsDigit('A'), "Character 'A' should not be identified as a digit"); + Assert.False(CharacterUtilities.IsDigit(' '), "Character ' ' should not be identified as a digit"); + Assert.False(CharacterUtilities.IsDigit('\0'), "Character '\\0' should not be identified as a digit"); + } } } diff --git a/src/Build/Evaluation/Conditionals/CharacterUtilities.cs b/src/Build/Evaluation/Conditionals/CharacterUtilities.cs index ed5502e91ca..5601d0491ab 100644 --- a/src/Build/Evaluation/Conditionals/CharacterUtilities.cs +++ b/src/Build/Evaluation/Conditionals/CharacterUtilities.cs @@ -9,7 +9,7 @@ internal static class CharacterUtilities { internal static bool IsNumberStart(char candidate) { - return candidate == '+' || candidate == '-' || candidate == '.' || char.IsDigit(candidate); + return candidate == '+' || candidate == '-' || candidate == '.' || IsDigit(candidate); } internal static bool IsSimpleStringStart(char candidate) @@ -19,12 +19,17 @@ internal static bool IsSimpleStringStart(char candidate) internal static bool IsSimpleStringChar(char candidate) { - return IsSimpleStringStart(candidate) || char.IsDigit(candidate); + return IsSimpleStringStart(candidate) || IsDigit(candidate); + } + + internal static bool IsDigit(char candidate) + { + return candidate >= '0' && candidate <= '9'; } internal static bool IsHexDigit(char candidate) { - return char.IsDigit(candidate) || ((uint)((candidate | 0x20) - 'a') <= 'f' - 'a'); + return IsDigit(candidate) || ((uint)((candidate | 0x20) - 'a') <= 'f' - 'a'); } } } diff --git a/src/Build/Evaluation/Conditionals/Scanner.cs b/src/Build/Evaluation/Conditionals/Scanner.cs index 718ae73d23d..500ef93df91 100644 --- a/src/Build/Evaluation/Conditionals/Scanner.cs +++ b/src/Build/Evaluation/Conditionals/Scanner.cs @@ -772,7 +772,7 @@ private void SkipWhiteSpace() } private void SkipDigits() { - while (_parsePoint < _expression.Length && char.IsDigit(_expression[_parsePoint])) + while (_parsePoint < _expression.Length && CharacterUtilities.IsDigit(_expression[_parsePoint])) { _parsePoint++; } From 721ed1aa8ca5d4cd25944bb8c00c1197beb0b537 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:55:47 +0000 Subject: [PATCH 3/7] Add fast-path for Char.IsDigit in WellKnownFunctions Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- .../Evaluation/Expander_Tests.cs | 34 +++++++++++++++++++ src/Build.UnitTests/Scanner_Tests.cs | 21 ------------ .../Conditionals/CharacterUtilities.cs | 11 ++---- src/Build/Evaluation/Conditionals/Scanner.cs | 2 +- .../Evaluation/Expander/WellKnownFunctions.cs | 12 +++++++ 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 1da44037bef..b4f2c5d5a99 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -4741,6 +4741,40 @@ public void PropertyFunctionStringArrayGetValue() TestPropertyFunction("$(X.Split($([System.Convert]::ToString(`.`).ToCharArray())).GetValue($([System.Convert]::ToInt32(0))))", "X", "ab.cd", "ab"); } + /// + /// Test that Char.IsDigit fast-path works correctly + /// + [Fact] + public void PropertyFunctionCharIsDigit() + { + PropertyDictionary pg = new PropertyDictionary(); + + Expander expander = new Expander(pg, FileSystems.Default); + + // Test with digit characters + string result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('5'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('9'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + // Test with non-digit characters + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('a'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit(' '))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('/'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit(':'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + } + private void TestPropertyFunction(string expression, string propertyName, string propertyValue, string expected) { var properties = new PropertyDictionary(); diff --git a/src/Build.UnitTests/Scanner_Tests.cs b/src/Build.UnitTests/Scanner_Tests.cs index 5d98f7cdf10..da75fd75436 100644 --- a/src/Build.UnitTests/Scanner_Tests.cs +++ b/src/Build.UnitTests/Scanner_Tests.cs @@ -562,26 +562,5 @@ public void NegativeTests() Scanner lexer = new Scanner("'$(DEBUG) == true", ParserOptions.AllowAll); Assert.False(lexer.Advance()); } - - /// - /// Tests the fast-path IsDigit method in CharacterUtilities. - /// - [Fact] - public void CharacterUtilities_IsDigit_WorksCorrectly() - { - // Test ASCII digits - for (char c = '0'; c <= '9'; c++) - { - Assert.True(CharacterUtilities.IsDigit(c), $"Character '{c}' should be identified as a digit"); - } - - // Test non-digit characters - Assert.False(CharacterUtilities.IsDigit('/'), "Character '/' should not be identified as a digit"); - Assert.False(CharacterUtilities.IsDigit(':'), "Character ':' should not be identified as a digit"); - Assert.False(CharacterUtilities.IsDigit('a'), "Character 'a' should not be identified as a digit"); - Assert.False(CharacterUtilities.IsDigit('A'), "Character 'A' should not be identified as a digit"); - Assert.False(CharacterUtilities.IsDigit(' '), "Character ' ' should not be identified as a digit"); - Assert.False(CharacterUtilities.IsDigit('\0'), "Character '\\0' should not be identified as a digit"); - } } } diff --git a/src/Build/Evaluation/Conditionals/CharacterUtilities.cs b/src/Build/Evaluation/Conditionals/CharacterUtilities.cs index 5601d0491ab..ed5502e91ca 100644 --- a/src/Build/Evaluation/Conditionals/CharacterUtilities.cs +++ b/src/Build/Evaluation/Conditionals/CharacterUtilities.cs @@ -9,7 +9,7 @@ internal static class CharacterUtilities { internal static bool IsNumberStart(char candidate) { - return candidate == '+' || candidate == '-' || candidate == '.' || IsDigit(candidate); + return candidate == '+' || candidate == '-' || candidate == '.' || char.IsDigit(candidate); } internal static bool IsSimpleStringStart(char candidate) @@ -19,17 +19,12 @@ internal static bool IsSimpleStringStart(char candidate) internal static bool IsSimpleStringChar(char candidate) { - return IsSimpleStringStart(candidate) || IsDigit(candidate); - } - - internal static bool IsDigit(char candidate) - { - return candidate >= '0' && candidate <= '9'; + return IsSimpleStringStart(candidate) || char.IsDigit(candidate); } internal static bool IsHexDigit(char candidate) { - return IsDigit(candidate) || ((uint)((candidate | 0x20) - 'a') <= 'f' - 'a'); + return char.IsDigit(candidate) || ((uint)((candidate | 0x20) - 'a') <= 'f' - 'a'); } } } diff --git a/src/Build/Evaluation/Conditionals/Scanner.cs b/src/Build/Evaluation/Conditionals/Scanner.cs index 500ef93df91..718ae73d23d 100644 --- a/src/Build/Evaluation/Conditionals/Scanner.cs +++ b/src/Build/Evaluation/Conditionals/Scanner.cs @@ -772,7 +772,7 @@ private void SkipWhiteSpace() } private void SkipDigits() { - while (_parsePoint < _expression.Length && CharacterUtilities.IsDigit(_expression[_parsePoint])) + while (_parsePoint < _expression.Length && char.IsDigit(_expression[_parsePoint])) { _parsePoint++; } diff --git a/src/Build/Evaluation/Expander/WellKnownFunctions.cs b/src/Build/Evaluation/Expander/WellKnownFunctions.cs index 5f75b6cb636..5d31b60fcae 100644 --- a/src/Build/Evaluation/Expander/WellKnownFunctions.cs +++ b/src/Build/Evaluation/Expander/WellKnownFunctions.cs @@ -875,6 +875,18 @@ internal static bool TryExecuteWellKnownFunction(string methodName, Type receive } } } + else if (receiverType == typeof(char)) + { + if (string.Equals(methodName, nameof(char.IsDigit), StringComparison.OrdinalIgnoreCase)) + { + if (ParseArgs.TryGetArg(args, out string? arg0) && arg0?.Length == 1) + { + char c = arg0[0]; + returnVal = c >= '0' && c <= '9'; + return true; + } + } + } else if (string.Equals(methodName, nameof(Regex.Replace), StringComparison.OrdinalIgnoreCase) && args.Length == 3) { if (ParseArgs.TryGetArgs(args, out string? arg1, out string? arg2, out string? arg3) && arg1 != null && arg2 != null && arg3 != null) From 116a6cb6ac807f5f2a4f02e4ccb61984aa5715a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:16:12 +0000 Subject: [PATCH 4/7] Use char.IsDigit instead of manual ASCII range check Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- src/Build/Evaluation/Expander/WellKnownFunctions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/Evaluation/Expander/WellKnownFunctions.cs b/src/Build/Evaluation/Expander/WellKnownFunctions.cs index 5d31b60fcae..442f6180a2a 100644 --- a/src/Build/Evaluation/Expander/WellKnownFunctions.cs +++ b/src/Build/Evaluation/Expander/WellKnownFunctions.cs @@ -882,7 +882,7 @@ internal static bool TryExecuteWellKnownFunction(string methodName, Type receive if (ParseArgs.TryGetArg(args, out string? arg0) && arg0?.Length == 1) { char c = arg0[0]; - returnVal = c >= '0' && c <= '9'; + returnVal = char.IsDigit(c); return true; } } From fda73b3c7cca8c521111be97b3bcf91166ebf90c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:33:58 +0000 Subject: [PATCH 5/7] Add support for Char.IsDigit(String, Int32) overload with comprehensive tests Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- .../Evaluation/Expander_Tests.cs | 23 +++++++++++++++++-- .../Evaluation/Expander/WellKnownFunctions.cs | 5 ++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index b4f2c5d5a99..4feb0f2336f 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -4751,7 +4751,7 @@ public void PropertyFunctionCharIsDigit() Expander expander = new Expander(pg, FileSystems.Default); - // Test with digit characters + // Test with digit characters - single char version string result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('5'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("True", result); @@ -4761,7 +4761,7 @@ public void PropertyFunctionCharIsDigit() result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('9'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("True", result); - // Test with non-digit characters + // Test with non-digit characters - single char version result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('a'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("False", result); @@ -4773,6 +4773,25 @@ public void PropertyFunctionCharIsDigit() result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit(':'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); Assert.Equal("False", result); + + // Test with string and index version + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 3))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 4))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 5))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 0))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("False", result); + + result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('hello789', 5))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Assert.Equal("True", result); } private void TestPropertyFunction(string expression, string propertyName, string propertyValue, string expected) diff --git a/src/Build/Evaluation/Expander/WellKnownFunctions.cs b/src/Build/Evaluation/Expander/WellKnownFunctions.cs index 442f6180a2a..a0b577585f3 100644 --- a/src/Build/Evaluation/Expander/WellKnownFunctions.cs +++ b/src/Build/Evaluation/Expander/WellKnownFunctions.cs @@ -885,6 +885,11 @@ internal static bool TryExecuteWellKnownFunction(string methodName, Type receive returnVal = char.IsDigit(c); return true; } + else if (ParseArgs.TryGetArgs(args, out string? str, out int index) && str != null) + { + returnVal = char.IsDigit(str, index); + return true; + } } } else if (string.Equals(methodName, nameof(Regex.Replace), StringComparison.OrdinalIgnoreCase) && args.Length == 3) From 949d5cd543fe83d07de78244afaeb658c883c827 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Jun 2025 07:09:43 +0000 Subject: [PATCH 6/7] Deduplicate returnVal assignment and return logic for Char.IsDigit overloads Co-authored-by: YuliiaKovalova <95473390+YuliiaKovalova@users.noreply.github.com> --- src/Build/Evaluation/Expander/WellKnownFunctions.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Build/Evaluation/Expander/WellKnownFunctions.cs b/src/Build/Evaluation/Expander/WellKnownFunctions.cs index a0b577585f3..e35c847123f 100644 --- a/src/Build/Evaluation/Expander/WellKnownFunctions.cs +++ b/src/Build/Evaluation/Expander/WellKnownFunctions.cs @@ -879,15 +879,21 @@ internal static bool TryExecuteWellKnownFunction(string methodName, Type receive { if (string.Equals(methodName, nameof(char.IsDigit), StringComparison.OrdinalIgnoreCase)) { + bool? result = null; + if (ParseArgs.TryGetArg(args, out string? arg0) && arg0?.Length == 1) { char c = arg0[0]; - returnVal = char.IsDigit(c); - return true; + result = char.IsDigit(c); } else if (ParseArgs.TryGetArgs(args, out string? str, out int index) && str != null) { - returnVal = char.IsDigit(str, index); + result = char.IsDigit(str, index); + } + + if (result.HasValue) + { + returnVal = result.Value; return true; } } From c2dbba7a2654d834acf3bbf298eddb03c93d2e58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Jun 2025 09:09:40 +0000 Subject: [PATCH 7/7] Rewrite PropertyFunctionCharIsDigit test as data-driven Theory using TestPropertyFunction helper Co-authored-by: rainersigwald <3347530+rainersigwald@users.noreply.github.com> --- .../Evaluation/Expander_Tests.cs | 68 ++++++------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 4feb0f2336f..c39c1c358aa 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -4744,54 +4744,26 @@ public void PropertyFunctionStringArrayGetValue() /// /// Test that Char.IsDigit fast-path works correctly /// - [Fact] - public void PropertyFunctionCharIsDigit() - { - PropertyDictionary pg = new PropertyDictionary(); - - Expander expander = new Expander(pg, FileSystems.Default); - - // Test with digit characters - single char version - string result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('5'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('0'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('9'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - // Test with non-digit characters - single char version - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('a'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit(' '))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('/'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit(':'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - // Test with string and index version - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 3))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 4))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 5))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 0))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('abc123def', 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("False", result); - - result = expander.ExpandIntoStringLeaveEscaped("$([System.Char]::IsDigit('hello789', 5))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - Assert.Equal("True", result); + [Theory] + // Test with digit characters - single char version + [InlineData("$([System.Char]::IsDigit('0'))", "True")] + [InlineData("$([System.Char]::IsDigit('5'))", "True")] + [InlineData("$([System.Char]::IsDigit('9'))", "True")] + // Test with non-digit characters - single char version + [InlineData("$([System.Char]::IsDigit('a'))", "False")] + [InlineData("$([System.Char]::IsDigit(' '))", "False")] + [InlineData("$([System.Char]::IsDigit('/'))", "False")] + [InlineData("$([System.Char]::IsDigit(':'))", "False")] + // Test with string and index version + [InlineData("$([System.Char]::IsDigit('abc123def', 3))", "True")] + [InlineData("$([System.Char]::IsDigit('abc123def', 4))", "True")] + [InlineData("$([System.Char]::IsDigit('abc123def', 5))", "True")] + [InlineData("$([System.Char]::IsDigit('abc123def', 0))", "False")] + [InlineData("$([System.Char]::IsDigit('abc123def', 2))", "False")] + [InlineData("$([System.Char]::IsDigit('hello789', 5))", "True")] + public void PropertyFunctionCharIsDigit(string expression, string expected) + { + TestPropertyFunction(expression, "dummy", "", expected); } private void TestPropertyFunction(string expression, string propertyName, string propertyValue, string expected)