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