diff --git a/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs b/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs
index 984afef972bc41..12299fad33fcf5 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/EncryptDecrypt.cs
@@ -43,9 +43,11 @@ public static void EncryptDecrypt_Read()
{
File.Encrypt(tmpFileName);
}
- catch (IOException e) when (e.HResult == unchecked((int)0x80070490))
+ catch (IOException e) when (e.HResult == unchecked((int)0x80070490) ||
+ (e.HResult == unchecked((int)0x80071776)))
{
// Ignore ERROR_NOT_FOUND 1168 (0x490). It is reported when EFS is disabled by domain policy.
+ // Ignore ERROR_NO_USER_KEYS (0x1776). This occurs when no user key exists to encrypt with.
return;
}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.cs
index e4f555bbc0e89d..846fcbce60fa65 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.cs
@@ -565,21 +565,6 @@ public partial class RegexParserTests
[InlineData(@"\bgr[ae]y\b", RegexOptions.None, null)]
[InlineData(@"\b((?# case sensitive comparison)D\w+)\s(?ixn)((?#case insensitive comparison)d\w+)\b", RegexOptions.None, null)]
[InlineData(@"\{\d+(,-*\d+)*(\:\w{1,4}?)*\}(?x) # Looks for a composite format item.", RegexOptions.None, null)]
- public void Parse(string pattern, RegexOptions options, object errorObj, int offset = -1)
- {
- RegexParseError? error = (RegexParseError?)errorObj;
-
- Assert.True(error == null || offset > 0, "All tests must be given positive offsets, or null if no offset should be tested.");
-
- // Parse the main tree and if parsing fails check if the supplied error matches.
- ParseTree(pattern, options, error, offset);
-
- // Assert that only ArgumentException might be thrown during parsing.
- ParseSubTrees(pattern, options);
- }
-
- [Theory]
- // Negative tests
[InlineData(@"cat([a-\d]*)dog", RegexOptions.None, RegexParseError.ShorthandClassInCharacterRange, 9)]
[InlineData(@"\k<1", RegexOptions.None, RegexParseError.UnrecognizedEscape, 2)]
[InlineData(@"(?')", RegexOptions.None, RegexParseError.CaptureGroupNameInvalid, 3)]
@@ -716,67 +701,67 @@ public void Parse(string pattern, RegexOptions options, object errorObj, int off
[InlineData("[a-z-[b][", RegexOptions.None, RegexParseError.UnterminatedBracket, 9)]
[InlineData("(?()|||||)", RegexOptions.None, RegexParseError.AlternationHasTooManyConditions, 10)]
[InlineData("[^]", RegexOptions.None, RegexParseError.UnterminatedBracket, 3)]
- [InlineData("\\", RegexOptions.None, RegexParseError.UnescapedEndingBackslash, 1)]
[InlineData("??", RegexOptions.None, RegexParseError.QuantifierAfterNothing, 1)]
[InlineData("(?=*)", RegexOptions.None, RegexParseError.QuantifierAfterNothing, 4)]
[InlineData("((((((*))))))", RegexOptions.None, RegexParseError.QuantifierAfterNothing, 7)]
- public void ParseCheckOffset(string pattern, RegexOptions options, object errorObj, int offset)
+ public void ParseCheckOffset(string pattern, RegexOptions options, RegexParseError? error, int offset = -1)
{
- RegexParseError? error = (RegexParseError?)errorObj;
-
- // Parse the main tree and if parsing fails check if the supplied error matches.
- ParseTree(pattern, options, error, offset);
-
- // Assert that only ArgumentException might be thrown during parsing.
- ParseSubTrees(pattern, options);
- }
-
-
- private static void ParseSubTrees(string pattern, RegexOptions options)
- {
- // Trim the input from the right and make sure tree invariants hold
- for (int i = pattern.Length - 1; i > 0; i--)
- {
- ParseSubTree(pattern.Substring(0, i), options);
- }
-
- // Trim the input from the left and make sure tree invariants hold
- for (int i = 1; i < pattern.Length; i++)
- {
- ParseSubTree(pattern.Substring(i), options);
- }
-
- // Skip middles
- for (int i = 1; i < pattern.Length; i++)
- {
- ParseSubTree(pattern.Substring(0, i) + pattern.Substring(i + 1), options);
- }
+ Parse(pattern, options, error, offset);
}
- static void ParseTree(string pattern, RegexOptions options, RegexParseError? error, int offset)
+ private static void Parse(string pattern, RegexOptions options, RegexParseError? error, int offset = -1)
{
if (error != null)
{
+ Assert.InRange(offset, 0, int.MaxValue);
Throws(error.Value, offset, () => new Regex(pattern, options));
return;
}
+ Assert.Equal(-1, offset);
+
// Nothing to assert here without having access to internals.
- new Regex(pattern, options);
+ new Regex(pattern, options); // Does not throw
+
+ ParsePatternFragments(pattern, options);
}
- private static void ParseSubTree(string pattern, RegexOptions options)
+ private static void ParsePatternFragments(string pattern, RegexOptions options)
{
- try
+ // Trim the input in various places and parse.
+ // Verify that if it throws, it's the correct exception type
+ for (int i = pattern.Length - 1; i > 0; i--)
+ {
+ string str = pattern.Substring(0, i);
+ MayThrow(() => new Regex(str, options));
+ }
+
+ for (int i = 1; i < pattern.Length; i++)
{
- new Regex(pattern, options);
+ string str = pattern.Substring(i);
+ MayThrow(() => new Regex(str, options));
}
- catch (ArgumentException)
+
+ for (int i = 1; i < pattern.Length; i++)
{
- // We are fine with ArgumentExceptions being thrown during sub expression parsing.
+ string str = pattern.Substring(0, i) + pattern.Substring(i + 1);
+ MayThrow(() => new Regex(str, options));
}
}
+ ///
+ /// Checks that action throws either a RegexParseException or an ArgumentException depending on the
+ /// environment and the supplied error.
+ ///
+ /// The expected parse error
+ /// The action to invoke.
static partial void Throws(RegexParseError error, int offset, Action action);
+
+ ///
+ /// Checks that action succeeds or throws either a RegexParseException or an ArgumentException depending on the
+ // environment and the action.
+ ///
+ /// The action to invoke.
+ static partial void MayThrow(Action action);
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netcoreapp.cs
index 9e246688ea6f9e..cc1d5f8658fe9b 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netcoreapp.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netcoreapp.cs
@@ -11,15 +11,11 @@ namespace System.Text.RegularExpressions.Tests
public partial class RegexParserTests
{
[Theory]
- [InlineData(@"[a-\-]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
- [InlineData(@"[a-\-b]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
- [InlineData(@"[a-\-\-b]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
- [InlineData(@"[a-\-\D]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
- [InlineData(@"[a-\-\-\D]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
- [InlineData(@"[a -\-\b]", RegexOptions.None, null, 5)]
- // OutOfMemoryException
+
+ // Avoid OutOfMemoryException
[InlineData("a{2147483647}", RegexOptions.None, null)]
[InlineData("a{2147483647,}", RegexOptions.None, null)]
+
[InlineData(@"(?(?N))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
[InlineData(@"(?(?i))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
[InlineData(@"(?(?I))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
@@ -30,7 +26,6 @@ public partial class RegexParserTests
[InlineData(@"(?(?X))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
[InlineData(@"(?(?n))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
[InlineData(@"(?(?m))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)]
- // IndexOutOfRangeException
[InlineData("(?<-", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
[InlineData("(?<-", RegexOptions.IgnorePatternWhitespace, RegexParseError.InvalidGroupingConstruct, 3)]
[InlineData(@"^[^<>]*(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)*(?(Open)(?!))$", RegexOptions.None, null)]
@@ -90,8 +85,50 @@ public partial class RegexParserTests
[InlineData("a{0,2147483648}", RegexOptions.None, RegexParseError.QuantifierOrCaptureGroupOutOfRange, 14)]
// Surrogate pair which is parsed as [char,char-char,char] as we operate on UTF-16 code units.
[InlineData("[\uD82F\uDCA0-\uD82F\uDCA3]", RegexOptions.IgnoreCase, RegexParseError.ReversedCharacterRange, 5)]
+
+ // Following are borrowed from Rust regex tests ============
+ // https://github.com/rust-lang/regex/blob/master/tests/noparse.rs
+ [InlineData(@"*", RegexOptions.None, RegexParseError.QuantifierAfterNothing, 1)]
+ [InlineData(@"[A-", RegexOptions.None, RegexParseError.UnterminatedBracket, 3)]
+ [InlineData(@"[A", RegexOptions.None, RegexParseError.UnterminatedBracket, 2)]
+ [InlineData(@"[\A]", RegexOptions.None, RegexParseError.UnrecognizedEscape, 3)]
+ [InlineData(@"[\z]", RegexOptions.None, RegexParseError.UnrecognizedEscape, 3)]
+ [InlineData(@"(", RegexOptions.None, RegexParseError.InsufficientClosingParentheses, 1)]
+ [InlineData(@")", RegexOptions.None, RegexParseError.InsufficientOpeningParentheses, 1)]
+ [InlineData(@"[a-Z]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 4)]
+ [InlineData(@"(?P<>a)", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
+ [InlineData(@"(?P)", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
+ [InlineData(@"(?a)a", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
+ [InlineData(@"a{2,1}", RegexOptions.None, RegexParseError.ReversedQuantifierRange, 6)]
+ [InlineData(@"(?", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 2)]
+ [InlineData(@"\8", RegexOptions.None, RegexParseError.UndefinedNumberedReference, 2)]
+ [InlineData(@"\xG0", RegexOptions.None, RegexParseError.InsufficientOrInvalidHexDigits, 3)]
+ [InlineData(@"\xF", RegexOptions.None, RegexParseError.InsufficientOrInvalidHexDigits, 2)]
+ [InlineData(@"\x{fffg}", RegexOptions.None, RegexParseError.InsufficientOrInvalidHexDigits, 3)]
+ [InlineData(@"(?a)", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
+ [InlineData(@"(?)", RegexOptions.None, RegexParseError.QuantifierAfterNothing, 2)]
+ [InlineData(@"(?P.)(?P.)", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)]
+ [InlineData(@"[a-\A]", RegexOptions.None, RegexParseError.UnrecognizedEscape, 5)]
+ [InlineData(@"[a-\z]", RegexOptions.None, RegexParseError.UnrecognizedEscape, 5)]
+ [InlineData(@"[a-\b]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a-\-]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a-\-b]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a-\-\-b]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a-\-\D]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a-\-\-\D]", RegexOptions.None, RegexParseError.ReversedCharacterRange, 5)]
+ [InlineData(@"[a -\-\b]", RegexOptions.None, null)]
+ [InlineData(@"[\b]", RegexOptions.None, null)] // errors in rust: class_no_boundary
+ [InlineData(@"a{10000000}", RegexOptions.None, null)] // errors in rust: too_big
+ [InlineData(@"a{1001", RegexOptions.None, null)] // errors in rust: counted_no_close
+ [InlineData(@"a{-1,1}", RegexOptions.None, null)] // errors in rust: counted_nonnegative
+ [InlineData(@"\\", RegexOptions.None, null)] // errors in rust: unfinished_escape
+ [InlineData(@"(?-i-i)", RegexOptions.None, null)] // errors in rust: double_neg
+ [InlineData(@"(?i-)", RegexOptions.None, null)] // errors in rust: neg_empty
+ [InlineData(@"[a-[:lower:]]", RegexOptions.None, null)] // errors in rust: range_end_no_class
+ // End of Rust parser tests ==============
+
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
- public void Parse_Netcoreapp(string pattern, RegexOptions options, object error, int offset = -1)
+ public void Parse_Netcoreapp(string pattern, RegexOptions options, RegexParseError? error, int offset = -1)
{
Parse(pattern, options, error, offset);
}
@@ -137,7 +174,7 @@ static partial void Throws(RegexParseError error, int offset, Action action)
return;
}
- throw new XunitException($"Expected RegexParseException with error: ({error}) -> Actual error: {regexParseError})");
+ throw new XunitException($"Expected RegexParseException with error {error} offset {offset} -> Actual error: {regexParseError} offset {e.Offset})");
}
catch (Exception e)
{
@@ -146,5 +183,18 @@ static partial void Throws(RegexParseError error, int offset, Action action)
throw new XunitException($"Expected RegexParseException with error: ({error}) -> Actual: No exception thrown");
}
+
+ ///
+ /// Checks that action succeeds or throws either a RegexParseException or an ArgumentException depending on the
+ // environment and the action.
+ ///
+ /// The action to invoke.
+ static partial void MayThrow(Action action)
+ {
+ if (Record.Exception(action) is Exception e && e is not RegexParseException)
+ {
+ throw new XunitException($"Expected RegexParseException or no exception -> Actual: ({e})");
+ }
+ }
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netfx.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netfx.cs
index 4e9006e8a130b5..e70d29a8dd388f 100644
--- a/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netfx.cs
+++ b/src/libraries/System.Text.RegularExpressions/tests/RegexParserTests.netfx.cs
@@ -11,7 +11,7 @@ namespace System.Text.RegularExpressions.Tests
public partial class RegexParserTests
{
///
- /// Checks if action throws either a RegexParseException or an ArgumentException depending on the
+ /// Checks that action throws either a RegexParseException or an ArgumentException depending on the
/// environment and the supplied error.
///
/// The expected parse error
@@ -28,11 +28,24 @@ static partial void Throws(RegexParseError error, int offset, Action action)
return;
}
catch (Exception e)
- {
+ {
throw new XunitException($"Expected ArgumentException -> Actual: {e}");
}
throw new XunitException($"Expected ArgumentException with error: ({error}) -> Actual: No exception thrown");
}
+
+ ///
+ /// Checks that action succeeds or throws either a RegexParseException or an ArgumentException depending on the
+ // environment and the action.
+ ///
+ /// The action to invoke.
+ static partial void MayThrow(Action action)
+ {
+ if (Record.Exception(action) is Exception e && e is not ArgumentException)
+ {
+ throw new XunitException($"Expected ArgumentException or no exception -> Actual: ({e})");
+ }
+ }
}
}
diff --git a/src/libraries/System.Text.RegularExpressions/tests/THIRD-PARTY-NOTICES.TXT b/src/libraries/System.Text.RegularExpressions/tests/THIRD-PARTY-NOTICES.TXT
new file mode 100644
index 00000000000000..8c51928cfb1e72
--- /dev/null
+++ b/src/libraries/System.Text.RegularExpressions/tests/THIRD-PARTY-NOTICES.TXT
@@ -0,0 +1,38 @@
+.NET Runtime uses third-party libraries or other resources that may be
+distributed under licenses different than the .NET Runtime software.
+
+In the event that we accidentally failed to list a required notice, please
+bring it to our attention. Post an issue or email us:
+
+ dotnet@microsoft.com
+
+The attached notices are provided for information only.
+
+License notice for https://github.com/rust-lang/regex
+-------------------------------
+
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
\ No newline at end of file